diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..4e874c1
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,18 @@
+[submodule "root/usr/share/zsh/site-functions/zsh-autosuggestions"]
+ path = root/usr/share/zsh/site-functions/zsh-autosuggestions
+ url = https://github.com/zsh-users/zsh-autosuggestions
+[submodule "root/usr/share/zsh/site-functions/zsh-syntax-highlighting"]
+ path = root/usr/share/zsh/site-functions/zsh-syntax-highlighting
+ url = https://github.com/zsh-users/zsh-syntax-highlighting
+; [submodule "root/usr/share/zsh/site-functions/zsh-you-should-use"]
+; path = root/usr/share/zsh/site-functions/zsh-you-should-use
+; url = https://github.com/MichaelAquilina/zsh-you-should-use
+[submodule "root/usr/local/src/z.lua"]
+ path = root/usr/local/src/z.lua
+ url = https://github.com/skywind3000/z.lua
+[submodule "root/usr/local/src/Hyprland"]
+ path = root/usr/local/src/Hyprland
+ url = https://github.com/hyprwm/Hyprland
+[submodule "root/usr/local/src/eww"]
+ path = root/usr/local/src/eww
+ url = https://github.com/elkowar/eww
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/firefox/chrome/userChrome.css b/firefox/chrome/userChrome.css
new file mode 100644
index 0000000..cc19d5a
--- /dev/null
+++ b/firefox/chrome/userChrome.css
@@ -0,0 +1,6 @@
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); /* only needed once */
+
+/* full screen toolbars */
+#navigator-toolbox[inFullscreen] toolbar:not([collapsed="true"]) {
+ visibility:visible!important;
+}
diff --git a/firefox/ublock-My_filters.txt b/firefox/ublock-My_filters.txt
new file mode 100644
index 0000000..0483398
--- /dev/null
+++ b/firefox/ublock-My_filters.txt
@@ -0,0 +1,51 @@
+! Replace third-party frames with a click2load banner
+*$3p,frame,redirect=click2load.html
+
+! click2load exceptions
+@@||viewscreen.githubusercontent.com^$3p,frame,domain=github.com
+@@||www.redditmedia.com^$3p,frame,domain=www.reddit.com
+@@||cdn.embedly.com^$3p,frame
+@@||imgur.com^$3p,frame
+
+! Bad TLDs (from https://github.com/DandelionSprout/adfilt/blob/master/Dandelion%20Sprout's%20Anti-Malware%20List.txt)
+||agency^
+||bid^
+||cf^
+||ga^
+||gdn^
+||gq^
+||ooo^
+||loan^
+||ml^,domain=~lingva.ml
+||pw^
+||tk^
+||top^
+
+! Hide GDPR consent banners
+sat1.de##cmp-banner
+!meteoblue.com##.gdpr_message
+askubuntu.com##.js-consent-banner
+stackexchange.com##.js-consent-banner
+stackoverflow.com##.js-consent-banner
+gitbook.io##.r-1yzf0co.r-ymttw5.r-18u37iz.r-1quu1zo.r-1i7sdiz.r-rs99b7.r-156hn8l.r-1habvwh.css-1dbjc4n
+www.morgenpost.de##.footer .no-js
+www.morgenpost.de##+js(remove-class, no-js, html)
+
+! Hide/Block annoying elements
+stackoverflow.com###saves-launch-popover
+
+! Hide/Block ad banners
+
+! Privacy
+||collector.github.com^
+||api.github.com/_private/browser/errors
+||cmp.zdf.de^
+||discord.com/api/v*/science
+
+! XSS hardening on codebergs login page
+||codeberg.org/user/login^$script
+||codeberg.org/user/login^$inline-script
+||codeberg.org/user/login^$third-party
+
+! Badfilters
+meteoblue.com#@#.social-wrapper
diff --git a/firefox/ublock-My_rules.txt b/firefox/ublock-My_rules.txt
new file mode 100644
index 0000000..c8116b3
--- /dev/null
+++ b/firefox/ublock-My_rules.txt
@@ -0,0 +1,158 @@
+!! This is not a comment, this is a invalid line which gets silently dropped
+!! by uB if you paste into your dynamic filter rules
+
+!! Blocking mode: hard mode with click2load 3p-frames
+* * * noop
+* * 1p-script noop
+* * 3p block
+* * 3p-frame noop
+* * 3p-script block
+* * image noop
+* * inline-script noop
+behind-the-scene * * block
+
+!! Global CDN noops for common CDNs (mostly via CNAME)
+* akamai.net * noop
+* akamaiedge.net * noop
+* akamaihd.net * noop
+* akamaized.net * noop
+* b-cdn.net * noop
+* cdn.cloudflare.net * noop
+* cloudfront.net * noop
+* discourse-cdn.com * noop
+* edgecastcdn.net * noop
+* global.fastly.net * noop
+* hwcdn.net * noop
+* kxcdn.com * noop
+* bootstrapcdn.com * noop
+* map.fastly.net * noop
+* netdna-ssl.com * noop
+* wp.com * noop
+* ajax.googleapis.com * noop
+* jsdelivr.net * noop
+* unsplash.com * noop
+* cdn.embedly.com * noop
+* wixmp.com * noop
+
+!! Website building/caching tools
+* cloudflare.com * noop
+* prismic.io * noop
+* googlehosted.com * noop
+
+!! Website 3rd party utilities (trusted or simply necessary things)
+* maps.googleapis.com * noop
+* recaptcha.net * noop
+* imgur.com * noop
+* shields.io * noop
+* gravatar.com * noop
+
+!! Explicit blocks (even though we block all 3rd parties, explicitly block these to signify that they're evil)
+* fonts.googleapis.com * block
+* doubleclick.net * block
+* sentry.io * block
+* servedby-buysellads.com * block
+* facebook.com * block
+* facebook.net * block
+
+!! Per-site (mostly noop) settings
+
+! GitHub
+github.com avatars.githubusercontent.com * noop
+github.com githubassets.com * noop
+
+! Google
+accounts.google.com googleusercontent.com * noop
+accounts.google.com gstatic.com * noop
+accounts.google.com signaler-pa.googleapis.com * noop
+accounts.google.com youtube.com * noop
+
+developers.google.com gstatic.com * noop
+developers.google.com googleusercontent.com * noop
+
+drive.google.com googleusercontent.com * noop
+drive.google.com gstatic.com * noop
+
+docs.google.com googleusercontent.com * noop
+docs.google.com gstatic.com * noop
+
+mail.google.com googleusercontent.com * noop
+mail.google.com gstatic.com * noop
+
+translate.google.com googleusercontent.com * noop
+translate.google.com gstatic.com * noop
+
+www.youtube.com ggpht.com * noop
+www.youtube.com google.com * noop
+www.youtube.com googleusercontent.com * noop
+www.youtube.com googlevideo.com * noop
+www.youtube.com gstatic.com * noop
+www.youtube.com jnn-pa.googleapis.com * noop
+www.youtube.com ytimg.com * noop
+
+! Microsoft crap
+login.live.com * 3p noop
+login.live.com * 3p-frame noop
+login.live.com * 3p-script noop
+
+login.microsoftonline.com * 3p noop
+login.microsoftonline.com * 3p-frame noop
+login.microsoftonline.com * 3p-script noop
+
+outlook.live.com * 3p noop
+outlook.live.com * 3p-frame noop
+outlook.live.com * 3p-script noop
+
+outlook.office365.com * 3p noop
+outlook.office365.com * 3p-frame noop
+outlook.office365.com * 3p-script noop
+
+! Protonmail
+mail.proton.me * 3p noop
+mail.proton.me * 3p-frame noop
+mail.proton.me * 3p-script noop
+
+! Reddit
+www.reddit.com redditmedia.com * noop
+www.reddit.com redditstatic.com * noop
+www.reddit.com redd.it * noop
+
+! StackExchange
+stackexchange.com sstatic.net * noop
+stackexchange.com stackoverflow.com * noop
+
+stackoverflow.com sstatic.net * noop
+stackoverflow.com stackexchange.com * noop
+
+askubuntu.com sstatic.net * noop
+askubuntu.com stackexchange.com * noop
+askubuntu.com stackoverflow.com * noop
+
+superuser.com sstatic.net * noop
+superuser.com stackexchange.com * noop
+superuser.com stackoverflow.com * noop
+
+serverfault.com sstatic.net * noop
+serverfault.com stackexchange.com * noop
+serverfault.com stackoverflow.com * noop
+
+! Simplelogin
+app.simplelogin.io simplelogin.co * noop
+
+! Privacyguides
+www.privacyguides.org github.com * noop
+www.privacyguides.org privacyguides.github.io * noop
+www.privacyguides.org privacyguides.net * noop
+
+! Fontawesome
+fontawesome.com algolia.net * noop
+fontawesome.com algolianet.com * noop
+fontawesome.com fortawesome.com * noop
+
+! IMDb
+www.imdb.com media-amazon.com * noop
+www.imdb.com media-imdb.com * noop
+
+! Others
+docs.gtk.org gnome.org * noop
+letsgetrusty.com kartra.com * noop
+* readthedocs.io * noop
diff --git a/firefox/user-overrides.js b/firefox/user-overrides.js
new file mode 100644
index 0000000..bcb5bfc
--- /dev/null
+++ b/firefox/user-overrides.js
@@ -0,0 +1,76 @@
+/* --------------- PERSONAL ARKENFOX OVERRIDES --------------- ***/
+user_pref("_overrides.parrot", "Custom: Arkenfox overrides");
+
+/* Re-enabled single perf features ***/
+user_pref("keyword.enabled", true); // 0801 Enable searching from location bar (I trust my search engine)
+// user_pref("browser.search.suggest.enabled", true); // 0804 Enable search suggestions
+// user_pref("browser.urlbar.suggest.searches", true); // 0804 Enables search suggestions in the url-bar
+user_pref("network.http.referer.XOriginPolicy", 0); // 1601 Allow cross origin referrers (disabling breaks too much), I use Smart Referer extension instead
+user_pref("privacy.clearOnShutdown.sessions", true); // 2811 Retain HTTP Basic Auth on shutdown
+user_pref("signon.rememberSignons", false); // 5003 Disable saving passwords to FF, there's Bitwarden
+user_pref("security.nocertdb", true); // 5005 Don't cache certificates (stores them session-only)
+user_pref("browser.download.folderList", 1); // 5016 Always use default downloads folder, not previous folder for download location
+
+/* override recipe: enable session restore ***/
+user_pref("browser.startup.page", 3); // 0102 Enable session restore
+user_pref("privacy.clearOnShutdown.history", false); // 2811 Don't clear history on exit
+user_pref("privacy.cpd.history", false); // 2812 To match when you use Ctrl-Shift-Del
+user_pref("places.history.enabled", false); // 5013 Disable browsing and download history (allows no history with session restore)
+
+/* --------------- PERSONAL PRIVACY RULES --------------- ***/
+user_pref("_overrides.parrot", "Custom: Privacy rules");
+
+/* Deny some permission requests by default (prevent ask popups) ***/
+user_pref("permissions.default.microphone", 2); // Microphone
+user_pref("permissions.default.desktop-notification", 2); // Notifications
+user_pref("permissions.default.geo", 2); // Location
+
+/* Disable safebrowsing (sends data to google) ***/
+user_pref("browser.safebrowsing.downloads.remote.enabled", false);
+user_pref("browser.safebrowsing.phishing.enabled", false);
+user_pref("browser.safebrowsing.malware.enabled", false);
+
+/* Javascript hardening (might cause slowdowns/breakage) ***/
+// user_pref("javascript.options.ion", false); // Might cause slowdowns/breakage
+// user_pref("javascript.options.asmjs", false); // Might cause slowdowns/breakage
+// user_pref("javascript.options.wasm", false); // Completely disables WASM, for the security gain and speed benefit
+// user_pref("javascript.options.baselinejit", false); // Disable JIT compilation - usually breaks sites with a lot of javascript but is a huge security gain
+
+/* Mark Quad9 as trusted recursive resolver (TRR) for DNS over HTTPS (DoH) ***/
+user_pref("network.trr.mode", 2); // Use TRR first, and only if the secure resolution fails use the operating system resolver.
+user_pref("network.trr.uri", "https://dns.quad9.net:5053/dns-query"); // Resolver we want to use
+user_pref("network.trr.bootstrapAddress", "9.9.9.9"); // Address to lookup the quad9 DoH address (only used once for this lookup)
+
+/* Other Privacy hardenings ***/
+user_pref("geo.enabled", false); // Fully disable location access
+user_pref("media.hardwaremediakeys.enabled", false); // Disable control via media keys (some websites might be stealing these)
+user_pref("dom.webaudio.enabled",false); // Old, mostly unused API, likely utilized for fingerprinting, hasn't broken anything FOR ME
+
+/* --------------- PERSONAL NON-PRIVACY RULES --------------- ***/
+user_pref("_overrides.parrot", "Custom: Non-privacy rules");
+
+/* Annoyances ***/
+user_pref("browser.tabs.firefox-view", false); // Don't show firefox view tab
+user_pref("extensions.pocket.enabled", false); // Disable pocket
+user_pref("extensions.abuseReport.enabled", false); // Disable report extension to mozilla
+user_pref("identity.fxaccounts.enabled", false); // Disable sync entirely
+
+/* Urlbar suggestions ***/
+user_pref("browser.urlbar.suggest.openpage", false); // Disable suggestions of open pages
+user_pref("browser.urlbar.suggest.engines", false); // Disable suggestions of search engines
+user_pref("browser.urlbar.suggest.topsites", false); // Disable suggestions of top sites
+
+/* Styling changes ***/
+user_pref("browser.fullscreen.autohide", false); // Don't auto-hide tabs when firefox is in fullscreen
+user_pref("browser.toolbars.bookmarks.visibility", "always"); // Always show bookmarks toolbar
+user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true); // Enable profile customization with userChrome.css and userContent.css
+user_pref("ui.systemUsesDarkTheme", 1); // Enables `prefers-color-scheme` CSS media feature
+
+/* Other changes ***/
+user_pref("browser.preferences.experimental", true); // Show experimental options in about:preferences
+user_pref("browser.urlbar.suggest.calculator", true); // Calculator in urlbar
+user_pref("layout.spellcheckDefault", 2); // Enable spellcheck by default for all inputs
+user_pref("browser.quitShortcut.disabled", true); // Disable Ctrl+Q browser quit shortcut
+
+/* --------------- END --------------- ***/
+user_pref("_overrides.parrot", "Custom: success");
diff --git a/home/.cache/nv/.keep b/home/.cache/nv/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/home/.cache/python_history b/home/.cache/python_history
new file mode 100644
index 0000000..e69de29
diff --git a/home/.cache/zsh/history b/home/.cache/zsh/history
new file mode 100644
index 0000000..e69de29
diff --git a/home/.config/alacritty/alacritty.yml b/home/.config/alacritty/alacritty.yml
new file mode 100644
index 0000000..251749b
--- /dev/null
+++ b/home/.config/alacritty/alacritty.yml
@@ -0,0 +1,816 @@
+# Configuration for Alacritty, the GPU enhanced terminal emulator.
+
+# Import additional configuration files
+#
+# Imports are loaded in order, skipping all missing files, with the importing
+# file being loaded last. If a field is already present in a previous import, it
+# will be replaced.
+#
+# All imports must either be absolute paths starting with `/`, or paths relative
+# to the user's home directory starting with `~/`.
+#import:
+# - /path/to/alacritty.yml
+
+# Any items in the `env` entry below will be added as
+# environment variables. Some entries may override variables
+# set by alacritty itself.
+#env:
+ # TERM variable
+ #
+ # This value is used to set the `$TERM` environment variable for
+ # each instance of Alacritty. If it is not present, alacritty will
+ # check the local terminfo database and use `alacritty` if it is
+ # available, otherwise `xterm-256color` is used.
+ #TERM: alacritty
+
+window:
+ # Window dimensions (changes require restart)
+ #
+ # Number of lines/columns (not pixels) in the terminal. The number of columns
+ # must be at least `2`, while using a value of `0` for columns and lines will
+ # fall back to the window manager's recommended size.
+ #dimensions:
+ # columns: 0
+ # lines: 0
+
+ # Window position (changes require restart)
+ #
+ # Specified in number of pixels.
+ # If the position is not set, the window manager will handle the placement.
+ #position:
+ # x: 0
+ # y: 0
+
+ # Window padding (changes require restart)
+ #
+ # Blank space added around the window in pixels. This padding is scaled
+ # by DPI and the specified value is always added at both opposing sides.
+ padding:
+ x: 6
+ y: 6
+
+ # Background opacity
+ #
+ # Window opacity as a floating point number from `0.0` to `1.0`.
+ # The value `0.0` is completely transparent and `1.0` is opaque.
+ opacity: 0.9
+
+ # Spread additional padding evenly around the terminal content.
+ #dynamic_padding: false
+
+ # Window decorations
+ #
+ # Values for `decorations`:
+ # - full: Borders and title bar
+ # - none: Neither borders nor title bar
+ #
+ # Values for `decorations` (macOS only):
+ # - transparent: Title bar, transparent background and title bar buttons
+ # - buttonless: Title bar, transparent background and no title bar buttons
+ #decorations: full
+
+ # Startup Mode (changes require restart)
+ #
+ # Values for `startup_mode`:
+ # - Windowed
+ # - Maximized
+ # - Fullscreen
+ #
+ # Values for `startup_mode` (macOS only):
+ # - SimpleFullscreen
+ #startup_mode: Windowed
+
+ # Window title
+ #title: Alacritty
+
+ # Allow terminal applications to change Alacritty's window title.
+ #dynamic_title: true
+
+ # Window class (Linux/BSD only):
+ #class:
+ # Application instance name
+ #instance: Alacritty
+ # General application class
+ #general: Alacritty
+
+ # GTK theme variant (Linux/BSD only)
+ #
+ # Override the variant of the GTK theme. Commonly supported values are `dark`
+ # and `light`. Set this to `None` to use the default theme variant.
+ #gtk_theme_variant: None
+
+scrolling:
+ # Maximum number of lines in the scrollback buffer.
+ # Specifying '0' will disable scrolling.
+ history: 10000
+
+ # Scrolling distance multiplier.
+ #multiplier: 3
+
+# Font configuration
+font:
+ # Normal (roman) font face
+ normal:
+ # Font family
+ #
+ # Default:
+ # - (macOS) Menlo
+ # - (Linux/BSD) monospace
+ # - (Windows) Consolas
+ family: JetBrains Mono
+ #family: Comic Mono
+ #family: Source Code Pro
+
+ # The `style` can be specified to pick a specific face.
+ style: Medium
+
+ # Bold font face
+ #bold:
+ # Font family
+ #
+ # If the bold family is not specified, it will fall back to the
+ # value specified for the normal font.
+ #family: monospace
+ #family: Source Code Pro
+
+ # The `style` can be specified to pick a specific face.
+ #style: Bold
+
+ # Italic font face
+ #italic:
+ # Font family
+ #
+ # If the italic family is not specified, it will fall back to the
+ # value specified for the normal font.
+ #family: monospace
+ #family: Source Code Pro
+
+ # The `style` can be specified to pick a specific face.
+ #style: Italic
+
+ # Bold italic font face
+ #bold_italic:
+ # Font family
+ #
+ # If the bold italic family is not specified, it will fall back to the
+ # value specified for the normal font.
+ #family: monospace
+
+ # The `style` can be specified to pick a specific face.
+ #style: Bold Italic
+
+ # Point size
+ size: 11.0
+
+ # Offset is the extra space around each character. `offset.y` can be thought
+ # of as modifying the line spacing, and `offset.x` as modifying the letter
+ # spacing.
+ #offset:
+ # x: 0
+ # y: 0
+
+ # Glyph offset determines the locations of the glyphs within their cells with
+ # the default being at the bottom. Increasing `x` moves the glyph to the
+ # right, increasing `y` moves the glyph upward.
+ #glyph_offset:
+ # x: 0
+ # y: 0
+
+ # Thin stroke font rendering (macOS only)
+ #
+ # Thin strokes are suitable for retina displays, but for non-retina screens
+ # it is recommended to set `use_thin_strokes` to `false`.
+ #use_thin_strokes: true
+
+# If `true`, bold text is drawn using the bright color variants.
+draw_bold_text_with_bright_colors: false
+
+# Colors (Tomorrow Night)
+colors:
+ # Default colors
+ primary:
+ background: '#191919'
+ foreground: '#d8dee9'
+ #background: '#1d1f21'
+ #foreground: '#c5c8c6'
+
+ # Bright and dim foreground colors
+ #
+ # The dimmed foreground color is calculated automatically if it is not
+ # present. If the bright foreground color is not set, or
+ # `draw_bold_text_with_bright_colors` is `false`, the normal foreground
+ # color will be used.
+ #dim_foreground: '#828482'
+ #bright_foreground: '#eaeaea'
+
+ # Cursor colors
+ #
+ # Colors which should be used to draw the terminal cursor.
+ #
+ # Allowed values are CellForeground and CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #cursor:
+ # text: CellBackground
+ # cursor: CellForeground
+
+ # Vi mode cursor colors
+ #
+ # Colors for the cursor when the vi mode is active.
+ #
+ # Allowed values are CellForeground and CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #vi_mode_cursor:
+ # text: CellBackground
+ # cursor: CellForeground
+
+ # Search colors
+ #
+ # Colors used for the search bar and match highlighting.
+ #search:
+ # Allowed values are CellForeground and CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #matches:
+ # foreground: '#000000'
+ # background: '#ffffff'
+ #focused_match:
+ # foreground: CellBackground
+ # background: CellForeground
+
+ #bar:
+ # background: '#c5c8c6'
+ # foreground: '#1d1f21'
+
+ # Line indicator
+ #
+ # Color used for the indicator displaying the position in history during
+ # search and vi mode.
+ #
+ # By default, these will use the opposing primary color.
+ #line_indicator:
+ # foreground: None
+ # background: None
+
+ # Selection colors
+ #
+ # Colors which should be used to draw the selection area.
+ #
+ # Allowed values are CellForeground and CellBackground, which reference the
+ # affected cell, or hexadecimal colors like #ff00ff.
+ #selection:
+ # text: CellBackground
+ # background: CellForeground
+
+ # Normal colors
+ normal:
+ #black: '#191919'
+ black: '#46494d'
+ red: '#b02626'
+ green: '#40a62f'
+ yellow: '#f2e635'
+ blue: '#314ad0'
+ magenta: '#b30ad0'
+ cyan: '#32d0fc'
+ white: '#acadb1'
+
+ # Bright colors
+ bright:
+ black: '#666666'
+ red: '#ce2727'
+ green: '#47c930'
+ yellow: '#fff138'
+ blue: '#2e4bea'
+ magenta: '#cc15ed'
+ cyan: '#54d9ff'
+ white: '#dbdbdb'
+
+ # Dim colors
+ dim:
+ black: '#676f78'
+ red: '#b55454'
+ green: '#78a670'
+ yellow: '#faf380'
+ blue: '#707fd0'
+ magenta: '#c583d0'
+ cyan: '#8adaf1'
+ white: '#e0e3e7'
+
+ # Indexed Colors
+ #
+ # The indexed colors include all colors from 16 to 256.
+ # When these are not set, they're filled with sensible defaults.
+ #
+ # Example:
+ # `- { index: 16, color: '#ff00ff' }`
+ #
+ #indexed_colors: []
+
+# Bell
+#
+# The bell is rung every time the BEL control character is received.
+#bell:
+ # Visual Bell Animation
+ #
+ # Animation effect for flashing the screen when the visual bell is rung.
+ #
+ # Values for `animation`:
+ # - Ease
+ # - EaseOut
+ # - EaseOutSine
+ # - EaseOutQuad
+ # - EaseOutCubic
+ # - EaseOutQuart
+ # - EaseOutQuint
+ # - EaseOutExpo
+ # - EaseOutCirc
+ # - Linear
+ #animation: EaseOutExpo
+
+ # Duration of the visual bell flash in milliseconds. A `duration` of `0` will
+ # disable the visual bell animation.
+ #duration: 0
+
+ # Visual bell animation color.
+ #color: '#ffffff'
+
+ # Bell Command
+ #
+ # This program is executed whenever the bell is rung.
+ #
+ # When set to `command: None`, no command will be executed.
+ #
+ # Example:
+ # command:
+ # program: notify-send
+ # args: ["Hello, World!"]
+ #
+ #command: None
+
+#selection:
+ # This string contains all characters that are used as separators for
+ # "semantic words" in Alacritty.
+ #semantic_escape_chars: ",│`|:\"' ()[]{}<>\t"
+
+ # When set to `true`, selected text will be copied to the primary clipboard.
+ #save_to_clipboard: false
+
+#cursor:
+ # Cursor style
+ #style:
+ # Cursor shape
+ #
+ # Values for `shape`:
+ # - ▇ Block
+ # - _ Underline
+ # - | Beam
+ #shape: Block
+
+ # Cursor blinking state
+ #
+ # Values for `blinking`:
+ # - Never: Prevent the cursor from ever blinking
+ # - Off: Disable blinking by default
+ # - On: Enable blinking by default
+ # - Always: Force the cursor to always blink
+ #blinking: Off
+
+ # Vi mode cursor style
+ #
+ # If the vi mode cursor style is `None` or not specified, it will fall back to
+ # the style of the active value of the normal cursor.
+ #
+ # See `cursor.style` for available options.
+ #vi_mode_style: None
+
+ # Cursor blinking interval in milliseconds.
+ #blink_interval: 750
+
+ # If this is `true`, the cursor will be rendered as a hollow box when the
+ # window is not focused.
+ #unfocused_hollow: true
+
+ # Thickness of the cursor relative to the cell width as floating point number
+ # from `0.0` to `1.0`.
+ #thickness: 0.15
+
+# Live config reload (changes require restart)
+#live_config_reload: true
+
+# Shell
+#
+# You can set `shell.program` to the path of your favorite shell, e.g.
+# `/bin/fish`. Entries in `shell.args` are passed unmodified as arguments to the
+# shell.
+#
+# Default:
+# - (macOS) /bin/bash --login
+# - (Linux/BSD) user login shell
+# - (Windows) powershell
+#shell:
+# program: /bin/bash
+# args:
+# - --login
+
+# Startup directory
+#
+# Directory the shell is started in. If this is unset, or `None`, the working
+# directory of the parent process will be used.
+#working_directory: None
+
+# Send ESC (\x1b) before characters when alt is pressed.
+#alt_send_esc: true
+
+#mouse:
+ # Click settings
+ #
+ # The `double_click` and `triple_click` settings control the time
+ # alacritty should wait for accepting multiple clicks as one double
+ # or triple click.
+ #double_click: { threshold: 300 }
+ #triple_click: { threshold: 300 }
+
+ # If this is `true`, the cursor is temporarily hidden when typing.
+ #hide_when_typing: false
+
+ #url:
+ # URL launcher
+ #
+ # This program is executed when clicking on a text which is recognized as a
+ # URL. The URL is always added to the command as the last parameter.
+ #
+ # When set to `launcher: None`, URL launching will be disabled completely.
+ #
+ # Default:
+ # - (macOS) open
+ # - (Linux/BSD) xdg-open
+ # - (Windows) explorer
+ #launcher:
+ # program: xdg-open
+ # args: []
+
+ # URL modifiers
+ #
+ # These are the modifiers that need to be held down for opening URLs when
+ # clicking on them. The available modifiers are documented in the key
+ # binding section.
+ #modifiers: None
+
+# Mouse bindings
+#
+# Mouse bindings are specified as a list of objects, much like the key
+# bindings further below.
+#
+# To trigger mouse bindings when an application running within Alacritty
+# captures the mouse, the `Shift` modifier is automatically added as a
+# requirement.
+#
+# Each mouse binding will specify a:
+#
+# - `mouse`:
+#
+# - Middle
+# - Left
+# - Right
+# - Numeric identifier such as `5`
+#
+# - `action` (see key bindings)
+#
+# And optionally:
+#
+# - `mods` (see key bindings)
+#mouse_bindings:
+# - { mouse: Middle, action: PasteSelection }
+
+# Key bindings
+#
+# Key bindings are specified as a list of objects. For example, this is the
+# default paste binding:
+#
+# `- { key: V, mods: Control|Shift, action: Paste }`
+#
+# Each key binding will specify a:
+#
+# - `key`: Identifier of the key pressed
+#
+# - A-Z
+# - F1-F24
+# - Key0-Key9
+#
+# A full list with available key codes can be found here:
+# https://docs.rs/glutin/*/glutin/event/enum.VirtualKeyCode.html#variants
+#
+# Instead of using the name of the keys, the `key` field also supports using
+# the scancode of the desired key. Scancodes have to be specified as a
+# decimal number. This command will allow you to display the hex scancodes
+# for certain keys:
+#
+# `showkey --scancodes`.
+#
+# Then exactly one of:
+#
+# - `chars`: Send a byte sequence to the running application
+#
+# The `chars` field writes the specified string to the terminal. This makes
+# it possible to pass escape sequences. To find escape codes for bindings
+# like `PageUp` (`"\x1b[5~"`), you can run the command `showkey -a` outside
+# of tmux. Note that applications use terminfo to map escape sequences back
+# to keys. It is therefore required to update the terminfo when changing an
+# escape sequence.
+#
+# - `action`: Execute a predefined action
+#
+# - ToggleViMode
+# - SearchForward
+# Start searching toward the right of the search origin.
+# - SearchBackward
+# Start searching toward the left of the search origin.
+# - Copy
+# - Paste
+# - IncreaseFontSize
+# - DecreaseFontSize
+# - ResetFontSize
+# - ScrollPageUp
+# - ScrollPageDown
+# - ScrollHalfPageUp
+# - ScrollHalfPageDown
+# - ScrollLineUp
+# - ScrollLineDown
+# - ScrollToTop
+# - ScrollToBottom
+# - ClearHistory
+# Remove the terminal's scrollback history.
+# - Hide
+# Hide the Alacritty window.
+# - Minimize
+# Minimize the Alacritty window.
+# - Quit
+# Quit Alacritty.
+# - ToggleFullscreen
+# - SpawnNewInstance
+# Spawn a new instance of Alacritty.
+# - ClearLogNotice
+# Clear Alacritty's UI warning and error notice.
+# - ClearSelection
+# Remove the active selection.
+# - ReceiveChar
+# - None
+#
+# - Vi mode exclusive actions:
+#
+# - Open
+# Open URLs at the cursor location with the launcher configured in
+# `url.launcher`.
+# - ToggleNormalSelection
+# - ToggleLineSelection
+# - ToggleBlockSelection
+# - ToggleSemanticSelection
+# Toggle semantic selection based on `selection.semantic_escape_chars`.
+#
+# - Vi mode exclusive cursor motion actions:
+#
+# - Up
+# One line up.
+# - Down
+# One line down.
+# - Left
+# One character left.
+# - Right
+# One character right.
+# - First
+# First column, or beginning of the line when already at the first column.
+# - Last
+# Last column, or beginning of the line when already at the last column.
+# - FirstOccupied
+# First non-empty cell in this terminal row, or first non-empty cell of
+# the line when already at the first cell of the row.
+# - High
+# Top of the screen.
+# - Middle
+# Center of the screen.
+# - Low
+# Bottom of the screen.
+# - SemanticLeft
+# Start of the previous semantically separated word.
+# - SemanticRight
+# Start of the next semantically separated word.
+# - SemanticLeftEnd
+# End of the previous semantically separated word.
+# - SemanticRightEnd
+# End of the next semantically separated word.
+# - WordLeft
+# Start of the previous whitespace separated word.
+# - WordRight
+# Start of the next whitespace separated word.
+# - WordLeftEnd
+# End of the previous whitespace separated word.
+# - WordRightEnd
+# End of the next whitespace separated word.
+# - Bracket
+# Character matching the bracket at the cursor's location.
+# - SearchNext
+# Beginning of the next match.
+# - SearchPrevious
+# Beginning of the previous match.
+# - SearchStart
+# Start of the match to the left of the vi mode cursor.
+# - SearchEnd
+# End of the match to the right of the vi mode cursor.
+#
+# - Search mode exclusive actions:
+# - SearchFocusNext
+# Move the focus to the next search match.
+# - SearchFocusPrevious
+# Move the focus to the previous search match.
+# - SearchConfirm
+# - SearchCancel
+# - SearchClear
+# Reset the search regex.
+# - SearchDeleteWord
+# Delete the last word in the search regex.
+# - SearchHistoryPrevious
+# Go to the previous regex in the search history.
+# - SearchHistoryNext
+# Go to the next regex in the search history.
+#
+# - macOS exclusive actions:
+# - ToggleSimpleFullscreen
+# Enter fullscreen without occupying another space.
+#
+# - Linux/BSD exclusive actions:
+#
+# - CopySelection
+# Copy from the selection buffer.
+# - PasteSelection
+# Paste from the selection buffer.
+#
+# - `command`: Fork and execute a specified command plus arguments
+#
+# The `command` field must be a map containing a `program` string and an
+# `args` array of command line parameter strings. For example:
+# `{ program: "alacritty", args: ["-e", "vttest"] }`
+#
+# And optionally:
+#
+# - `mods`: Key modifiers to filter binding actions
+#
+# - Command
+# - Control
+# - Option
+# - Super
+# - Shift
+# - Alt
+#
+# Multiple `mods` can be combined using `|` like this:
+# `mods: Control|Shift`.
+# Whitespace and capitalization are relevant and must match the example.
+#
+# - `mode`: Indicate a binding for only specific terminal reported modes
+#
+# This is mainly used to send applications the correct escape sequences
+# when in different modes.
+#
+# - AppCursor
+# - AppKeypad
+# - Search
+# - Alt
+# - Vi
+#
+# A `~` operator can be used before a mode to apply the binding whenever
+# the mode is *not* active, e.g. `~Alt`.
+#
+# Bindings are always filled by default, but will be replaced when a new
+# binding with the same triggers is defined. To unset a default binding, it can
+# be mapped to the `ReceiveChar` action. Alternatively, you can use `None` for
+# a no-op if you do not wish to receive input characters for that binding.
+#
+# If the same trigger is assigned to multiple actions, all of them are executed
+# in the order they were defined in.
+#key_bindings:
+ #- { key: Paste, action: Paste }
+ #- { key: Copy, action: Copy }
+ #- { key: L, mods: Control, action: ClearLogNotice }
+ #- { key: L, mods: Control, mode: ~Vi|~Search, chars: "\x0c" }
+ #- { key: PageUp, mods: Shift, mode: ~Alt, action: ScrollPageUp, }
+ #- { key: PageDown, mods: Shift, mode: ~Alt, action: ScrollPageDown }
+ #- { key: Home, mods: Shift, mode: ~Alt, action: ScrollToTop, }
+ #- { key: End, mods: Shift, mode: ~Alt, action: ScrollToBottom }
+
+ # Vi Mode
+ #- { key: Space, mods: Shift|Control, mode: Vi|~Search, action: ScrollToBottom }
+ #- { key: Space, mods: Shift|Control, mode: ~Search, action: ToggleViMode }
+ #- { key: Escape, mode: Vi|~Search, action: ClearSelection }
+ #- { key: I, mode: Vi|~Search, action: ScrollToBottom }
+ #- { key: I, mode: Vi|~Search, action: ToggleViMode }
+ #- { key: C, mods: Control, mode: Vi|~Search, action: ToggleViMode }
+ #- { key: Y, mods: Control, mode: Vi|~Search, action: ScrollLineUp }
+ #- { key: E, mods: Control, mode: Vi|~Search, action: ScrollLineDown }
+ #- { key: G, mode: Vi|~Search, action: ScrollToTop }
+ #- { key: G, mods: Shift, mode: Vi|~Search, action: ScrollToBottom }
+ #- { key: B, mods: Control, mode: Vi|~Search, action: ScrollPageUp }
+ #- { key: F, mods: Control, mode: Vi|~Search, action: ScrollPageDown }
+ #- { key: U, mods: Control, mode: Vi|~Search, action: ScrollHalfPageUp }
+ #- { key: D, mods: Control, mode: Vi|~Search, action: ScrollHalfPageDown }
+ #- { key: Y, mode: Vi|~Search, action: Copy }
+ #- { key: Y, mode: Vi|~Search, action: ClearSelection }
+ #- { key: Copy, mode: Vi|~Search, action: ClearSelection }
+ #- { key: V, mode: Vi|~Search, action: ToggleNormalSelection }
+ #- { key: V, mods: Shift, mode: Vi|~Search, action: ToggleLineSelection }
+ #- { key: V, mods: Control, mode: Vi|~Search, action: ToggleBlockSelection }
+ #- { key: V, mods: Alt, mode: Vi|~Search, action: ToggleSemanticSelection }
+ #- { key: Return, mode: Vi|~Search, action: Open }
+ #- { key: K, mode: Vi|~Search, action: Up }
+ #- { key: J, mode: Vi|~Search, action: Down }
+ #- { key: H, mode: Vi|~Search, action: Left }
+ #- { key: L, mode: Vi|~Search, action: Right }
+ #- { key: Up, mode: Vi|~Search, action: Up }
+ #- { key: Down, mode: Vi|~Search, action: Down }
+ #- { key: Left, mode: Vi|~Search, action: Left }
+ #- { key: Right, mode: Vi|~Search, action: Right }
+ #- { key: Key0, mode: Vi|~Search, action: First }
+ #- { key: Key4, mods: Shift, mode: Vi|~Search, action: Last }
+ #- { key: Key6, mods: Shift, mode: Vi|~Search, action: FirstOccupied }
+ #- { key: H, mods: Shift, mode: Vi|~Search, action: High }
+ #- { key: M, mods: Shift, mode: Vi|~Search, action: Middle }
+ #- { key: L, mods: Shift, mode: Vi|~Search, action: Low }
+ #- { key: B, mode: Vi|~Search, action: SemanticLeft }
+ #- { key: W, mode: Vi|~Search, action: SemanticRight }
+ #- { key: E, mode: Vi|~Search, action: SemanticRightEnd }
+ #- { key: B, mods: Shift, mode: Vi|~Search, action: WordLeft }
+ #- { key: W, mods: Shift, mode: Vi|~Search, action: WordRight }
+ #- { key: E, mods: Shift, mode: Vi|~Search, action: WordRightEnd }
+ #- { key: Key5, mods: Shift, mode: Vi|~Search, action: Bracket }
+ #- { key: Slash, mode: Vi|~Search, action: SearchForward }
+ #- { key: Slash, mods: Shift, mode: Vi|~Search, action: SearchBackward }
+ #- { key: N, mode: Vi|~Search, action: SearchNext }
+ #- { key: N, mods: Shift, mode: Vi|~Search, action: SearchPrevious }
+
+ # Search Mode
+ #- { key: Return, mode: Search|Vi, action: SearchConfirm }
+ #- { key: Escape, mode: Search, action: SearchCancel }
+ #- { key: C, mods: Control, mode: Search, action: SearchCancel }
+ #- { key: U, mods: Control, mode: Search, action: SearchClear }
+ #- { key: W, mods: Control, mode: Search, action: SearchDeleteWord }
+ #- { key: P, mods: Control, mode: Search, action: SearchHistoryPrevious }
+ #- { key: N, mods: Control, mode: Search, action: SearchHistoryNext }
+ #- { key: Up, mode: Search, action: SearchHistoryPrevious }
+ #- { key: Down, mode: Search, action: SearchHistoryNext }
+ #- { key: Return, mode: Search|~Vi, action: SearchFocusNext }
+ #- { key: Return, mods: Shift, mode: Search|~Vi, action: SearchFocusPrevious }
+
+ # (Windows, Linux, and BSD only)
+ #- { key: V, mods: Control|Shift, mode: ~Vi, action: Paste }
+ #- { key: C, mods: Control|Shift, action: Copy }
+ #- { key: F, mods: Control|Shift, mode: ~Search, action: SearchForward }
+ #- { key: B, mods: Control|Shift, mode: ~Search, action: SearchBackward }
+ #- { key: C, mods: Control|Shift, mode: Vi|~Search, action: ClearSelection }
+ #- { key: Insert, mods: Shift, action: PasteSelection }
+ #- { key: Key0, mods: Control, action: ResetFontSize }
+ #- { key: Equals, mods: Control, action: IncreaseFontSize }
+ #- { key: Plus, mods: Control, action: IncreaseFontSize }
+ #- { key: NumpadAdd, mods: Control, action: IncreaseFontSize }
+ #- { key: Minus, mods: Control, action: DecreaseFontSize }
+ #- { key: NumpadSubtract, mods: Control, action: DecreaseFontSize }
+
+ # (Windows only)
+ #- { key: Return, mods: Alt, action: ToggleFullscreen }
+
+ # (macOS only)
+ #- { key: K, mods: Command, mode: ~Vi|~Search, chars: "\x0c" }
+ #- { key: K, mods: Command, mode: ~Vi|~Search, action: ClearHistory }
+ #- { key: Key0, mods: Command, action: ResetFontSize }
+ #- { key: Equals, mods: Command, action: IncreaseFontSize }
+ #- { key: Plus, mods: Command, action: IncreaseFontSize }
+ #- { key: NumpadAdd, mods: Command, action: IncreaseFontSize }
+ #- { key: Minus, mods: Command, action: DecreaseFontSize }
+ #- { key: NumpadSubtract, mods: Command, action: DecreaseFontSize }
+ #- { key: V, mods: Command, action: Paste }
+ #- { key: C, mods: Command, action: Copy }
+ #- { key: C, mods: Command, mode: Vi|~Search, action: ClearSelection }
+ #- { key: H, mods: Command, action: Hide }
+ #- { key: M, mods: Command, action: Minimize }
+ #- { key: Q, mods: Command, action: Quit }
+ #- { key: W, mods: Command, action: Quit }
+ #- { key: N, mods: Command, action: SpawnNewInstance }
+ #- { key: F, mods: Command|Control, action: ToggleFullscreen }
+ #- { key: F, mods: Command, mode: ~Search, action: SearchForward }
+ #- { key: B, mods: Command, mode: ~Search, action: SearchBackward }
+
+#debug:
+ # Display the time it takes to redraw each frame.
+ #render_timer: false
+
+ # Keep the log file after quitting Alacritty.
+ #persistent_logging: false
+
+ # Log level
+ #
+ # Values for `log_level`:
+ # - Off
+ # - Error
+ # - Warn
+ # - Info
+ # - Debug
+ # - Trace
+ #log_level: Warn
+
+ # Print all received window events.
+ #print_events: false
diff --git a/home/.config/dunst/dunstrc b/home/.config/dunst/dunstrc
new file mode 100644
index 0000000..59f3213
--- /dev/null
+++ b/home/.config/dunst/dunstrc
@@ -0,0 +1,443 @@
+[global]
+
+ ### Display ###
+
+ # Which monitor should the notifications be shown on
+ monitor = 0
+
+ # Display notifications on focused monitor. Possible modes:
+ # mouse: follow mouse pointer
+ # keyboard: follow window with keyboard focus
+ # none: don't follow anything
+ #
+ # keyboard needs a window manager that exports
+ # _NET_ACTIVE_WINDOW propery! This should be the case for almost
+ # all modern window managers.
+ #
+ # If this option isn't none, monitor option will be ignored.
+ follow = mouse
+
+ ### Geometry ###
+
+ # Dynamic width from 0 to 300
+ # width = (0, 300)
+ # constant width of 300
+ # width = 300
+ width = 270
+
+ # The maximum height of a single notification, excluding the frame.
+ height = 300
+
+ # Position the notification in the top right corner
+ origin = top-right
+
+ # Offset from the origin
+ offset = 30x30
+
+ # Scale factor. It is auto-detected if value is 0.
+ scale = 0
+
+ # Maximum number of notifications (0 means no limit)
+ notification_limit = 0
+
+ ### Progress bar ###
+
+ # Turn on the progress bar. It appears when a progress hint is passed
+ # with for example dunstify -h int:value:12
+ progress_bar = true
+
+ # Set the progress bar height. This includes the frame, so make sure
+ # it's at least twice as big as the frame width.
+ progress_bar_height = 30
+
+ # Set the frame width of the progress bar
+ progress_bar_frame_width = 1
+
+ # Set the minimum width for the progress bar
+ progress_bar_min_width = 150
+
+ # Set the maximum width for the progress bar
+ progress_bar_max_width = 300
+
+ # Show how many messages are currently hidden (because of
+ # notification_limit).
+ indicate_hidden = yes
+
+ # The transparency of the window. Range: [0; 100].
+ # This option will only work if a compositing window manager is
+ # present (e.g. xcompmgr, compiz, picom, etc.). (X11 only)
+ transparency = 20
+
+ # Draw a line of "separator_height" pixel height between two
+ # notifications. Set to 0 to disable.
+ separator_height = 2
+
+ # Padding between text and separator.
+ padding = 10
+
+ # Horizontal padding
+ horizontal_padding = 10
+
+ # Padding between text and icon.
+ text_icon_padding = 0
+
+ # Defines width in pixels of fram around the notification window.
+ # Set to 0 to disable.
+ frame_width = 3
+
+ # Defines color of the frame around the notification window
+ frame_color = "#aaaaaa"
+
+ # Define a color for the separator.
+ # possible values are:
+ # * auto: dunst tries to find a color fitting to the background;
+ # * foreground: use the same color as the foreground;
+ # * frame: use the same color as the frame;
+ # * anything else will be interpreted as a X color.
+ separator_color = frame
+
+ # Sort messages by urgency.
+ sort = yes
+
+ # Don't remove messages if the user is idle (no mouse/keyboard input)
+ # for longer than idle_threshold seconds (0 to disable)
+ # A client can set the 'transient' hint to bypass this. See the rules
+ # section for how to disable this if necessary
+ idle_threshold = 120
+
+ ### Text ###
+ font = JetBrains Mono 11
+
+ # The spacing between the lines. If the height is smaller than the
+ # font height, it will get raised to the font height.
+ line_height = 0
+
+ # Possible values are:
+ # full: Allow a small subset of html markup in notifications:
+ # bold
+ # italic
+ # strikethrough
+ # underline
+ #
+ # For a complete reference see
+ # .
+ #
+ # strip: This setting is provided for compatibility with some broken
+ # clients that send markup even though it's not enabled on the
+ # server. Dunst will try to strip the markup but the parsing is
+ # simplistic so using this option outside of matching rules for
+ # specific applications *IS GREATLY DISCOURAGED*.
+ #
+ # no: Disable markup parsing, incoming notifications will be treated as
+ # plain text. Dunst will not advertise that it has the body-markup
+ # capability if this is set as a global setting.
+ #
+ # It's important to note that markup inside the format option will be parsed
+ # regardless of what this is set to.
+ markup = full
+
+ # The format of the message. Possible variables are:
+ # %a appname
+ # %s summary
+ # %b body
+ # %i iconname (including its path)
+ # %I iconname (without its path)
+ # %p progress value if set ([ 0%] to [100%]) or nothing
+ # %n progress value if set without any extra characters
+ # %% Literal %
+ # Markup is allowed
+ format = "%a - %s\n%b"
+
+ # Alignment of the message text.
+ # Possible values are "left", "center" and "right".
+ alignment = left
+
+ # Vertical alignment of message text and icon.
+ # Possible values are "top", "center" and "bottom".
+ vertical_alignment = center
+
+ # Wrap longer sentences which don't fit into the horizonal size
+ # of the noticication. If set to no, longer sententences will be truncated
+ word_wrap = yes
+
+ # Specify where to make an ellipsis in the long lines.
+ # Possible values are "start", "middle", "end".
+ ellipsize = middle
+
+ # Ignore newlines '\n' in notifications.
+ ignore_newline = no
+
+ # Show age of message if message is older than show_age_threshold seconds
+ # Set to -1 to disable, 0 to always show.
+ show_age_threshold = 60
+
+ # Merge multiple notifications with the same content
+ stack_duplicates = true
+
+ # Hide the count of merged notifications with the same content
+ hide_duplicate_count = false
+
+ # Display indicators for URLs (U) and actions (A)
+ show_indicators = yes
+
+ ### Icons ###
+
+ # Align icons left/right/off
+ icon_position = left
+
+ # Scale small icons up to this size, set to 0 to disable. Helpful
+ # for e.g. small files or high-dpi screens. In case of conflict,
+ # max_icon_size takes precedence over this.
+ min_icon_size = 0
+
+ # Scale larger icons down to this size, set to 0 to disable
+ max_icon_size = 32
+
+ # Paths to default icons
+ icon_path = /usr/share/icons/hicolor/16x16/status/:/usr/share/icons/hicolor/16x16/devices/:/usr/share/icons/hicolor/16x16/apps/
+
+ ### History ###
+
+ # Should a notification popped up from history be sticky or timeout
+ # as if it would normally do.
+ sticky_history = yes
+
+ # Maximum amount of notifications kept in history
+ history_length = 20
+
+ ### Misc/Advanced ###
+
+ # dmenu path
+ dmenu = /usr/local/bin/dmenu -p dunst:
+
+ # Browser for opening urls in content menu
+ browser = /usr/bin/xdg-open
+
+ # Always run rule-defined scripts, even if the notification is suppressed
+ always_run_script = true
+
+ # Define the title of the windows spawned by dunst
+ title = Dunst
+
+ # Define the class of the windows spawned by dunst
+ class = Dunst
+
+ # Define the corner radius of the notification window
+ # in pixel size. If the radius is 0, you have no rounded
+ # corners.
+ # The radius will be automatically lowered if it exceeds half of the
+ # notification height to avoid clipping text and/or icons.
+ corner_radius = 0
+
+ # Ignore the dbus closeNotification message.
+ # Useful to enforce the timeout set by dunst configuration. Without this
+ # parameter, an application may close the notification sent before the
+ # user defined timeout.
+ ignore_dbusclose = false
+
+ ### Wayland ###
+ # These settings are Wayland-specific. They have no effect when using X11
+
+ # Uncomment this if you want to let notications appear under fullscreen
+ # applications (default: overlay)
+ # layer = top
+
+ # Set this to true to use X11 output on Wayland.
+ force_xwayland = false
+
+ ### Legacy ###
+
+ # Use the Xinerama extension instead of RandR for multi-monitor support.
+ # This setting is provided for compatibility with older nVidia drivers that
+ # do not support RandR and using it on systems that support RandR is highly
+ # discouraged.
+ #
+ # By enabling this setting dunst will not be able to detect when a monitor
+ # is connected or disconnected which might break follow mode if the screen
+ # layout changes.
+ force_xinerama = false
+
+ ### Mouse ###
+
+ # Defines list of actions for each mouse event
+ # Possible values are:
+ # * none: Don't do anything.
+ # * do_action: Invoke the action determined by the action_name rule. If there is no
+ # such action, open the context menu.
+ # * open_url: If the notification has exactly one url, open it. If there are multiple
+ # ones, open the context menu.
+ # * close_current: Close current notification.
+ # * close_all: Close all notifications.
+ # * context: Open context menu for the notification.
+ # * context_all: Open context menu for all notifications.
+ # These values can be strung together for each mouse event, and
+ # will be executed in sequence.
+ mouse_left_click = do_action, open_url, close_current
+ mouse_middle_click = context
+ mouse_right_click = close_current
+
+# Experimental features that may or may not work correctly. Do not expect them
+# to have a consistent behaviour across releases.
+[experimental]
+ # Calculate the dpi to use on a per-monitor basis.
+ # If this setting is enabled the Xft.dpi value will be ignored and instead
+ # dunst will attempt to calculate an appropriate dpi value for each monitor
+ # using the resolution and physical size. This might be useful in setups
+ # where there are multiple screens with very different dpi values.
+ per_monitor_dpi = false
+
+[urgency_low]
+ highlight = "#fe6c5a"
+ background = "#1e2137fa"
+ frame_color = "#27292c"
+ foreground = "#ffffff"
+
+ timeout = 5
+ # Icon for notifications with low urgency, uncomment to enable
+ #icon = /path/to/icon
+
+[urgency_normal]
+ highlight = "#fe6c5a"
+ background = "#141c21fa"
+ frame_color = "#27292c"
+ foreground = "#ffffffff"
+
+ timeout = 10
+ # Icon for notifications with normal urgency, uncomment to enable
+ #icon = /path/to/icon
+
+[urgency_critical]
+ highlight = "#fe6c5a"
+ background = "#dd130ddd"
+ frame_color = "#27292c"
+ foreground = "#ffffffff"
+
+ timeout = 0
+ icon = arbt
+ # Icon for notifications with critical urgency, uncomment to enable
+ #icon = /path/to/icon
+
+
+# Every section that isn't one of the above is interpreted as a rules to
+# override settings for certain messages.
+#
+# Messages can be matched by
+# appname (discouraged, see desktop_entry)
+# body
+# category
+# desktop_entry
+# icon
+# match_transient
+# msg_urgency
+# stack_tag
+# summary
+#
+# and you can override the
+# background
+# foreground
+# format
+# frame_color
+# fullscreen
+# new_icon
+# set_stack_tag
+# set_transient
+# set_category
+# timeout
+# urgency
+# icon_position
+# skip_display
+# history_ignore
+# action_name
+# word_wrap
+# ellipsize
+# alignment
+# hide_text
+#
+# Shell-like globbing will get expanded.
+#
+# Instead of the appname filter, it's recommended to use the desktop_entry filter.
+# GLib based applications export their desktop-entry name. In comparison to the appname,
+# the desktop-entry won't get localized.
+#
+# SCRIPTING
+# You can specify a script that gets run when the rule matches by
+# setting the "script" option.
+# The script will be called as follows:
+# script appname summary body icon urgency
+# where urgency can be "LOW", "NORMAL" or "CRITICAL".
+#
+# NOTE: It might be helpful to run dunst -print in a terminal in order
+# to find fitting options for rules.
+
+# Disable the transient hint so that idle_threshold cannot be bypassed from the
+# client
+#[transient_disable]
+# match_transient = yes
+# set_transient = no
+#
+# Make the handling of transient notifications more strict by making them not
+# be placed in history.
+#[transient_history_ignore]
+# match_transient = yes
+# history_ignore = yes
+
+# fullscreen values
+# show: show the notifications, regardless if there is a fullscreen window opened
+# delay: displays the new notification, if there is no fullscreen window active
+# If the notification is already drawn, it won't get undrawn.
+# pushback: same as delay, but when switching into fullscreen, the notification will get
+# withdrawn from screen again and will get delayed like a new notification
+#[fullscreen_delay_everything]
+# fullscreen = delay
+#[fullscreen_show_critical]
+# msg_urgency = critical
+# fullscreen = show
+
+#[espeak]
+# summary = "*"
+# script = dunst_espeak.sh
+
+#[script-test]
+# summary = "*script*"
+# script = dunst_test.sh
+
+#[ignore]
+# # This notification will not be displayed
+# summary = "foobar"
+# skip_display = true
+
+#[history-ignore]
+# # This notification will not be saved in history
+# summary = "foobar"
+# history_ignore = yes
+
+#[skip-display]
+# # This notification will not be displayed, but will be included in the history
+# summary = "foobar"
+# skip_display = yes
+
+#[signed_on]
+# appname = Pidgin
+# summary = "*signed on*"
+# urgency = low
+#
+#[signed_off]
+# appname = Pidgin
+# summary = *signed off*
+# urgency = low
+#
+#[says]
+# appname = Pidgin
+# summary = *says*
+# urgency = critical
+#
+#[twitter]
+# appname = Pidgin
+# summary = *twitter.com*
+# urgency = normal
+#
+#[stack-volumes]
+# appname = "some_volume_notifiers"
+# set_stack_tag = "volume"
+#
+# vim: ft=cfg
diff --git a/home/.config/eww/css/_colors.scss b/home/.config/eww/css/_colors.scss
new file mode 100644
index 0000000..1534b69
--- /dev/null
+++ b/home/.config/eww/css/_colors.scss
@@ -0,0 +1,43 @@
+$rosewater: #f5e0dc;
+$flamingo: #f2cdcd;
+$pink: #f5c2e7;
+$mauve: #cba6f7;
+$red: #f38ba8;
+$maroon: #eba0ac;
+$peach: #fab387;
+$yellow: #f9e2af;
+$gold: #efcb10;
+$green: #a6e3a1;
+$lime: #78db32;
+$teal: #94e2d5;
+$sky: #89dceb;
+$sapphire: #74c7ec;
+$blue: #89b4fa;
+$lavender: #b4befe;
+$orange: #ffa500;
+
+$text: #cdd6f4;
+$subtext1: #bac2de;
+$subtext0: #a6adc8;
+$overlay2: #9399b2;
+$overlay1: #7f849c;
+$overlay0: #6c7086;
+
+$surface2: #585b70;
+$surface1: #45475a;
+$surface0: #313244;
+
+$base-a: rgba(30, 30, 40, 0.65);
+$base: rgba(30, 30, 40, 1);
+$base1-a: rgba(49, 50, 68, 0.85);
+$base1: rgba(49, 50, 68, 1);
+$mantle: #181825;
+$crust: #11111b;
+
+$fg: $text;
+$bg-a: $base-a;
+$bg: $base;
+$bg1: $base1;
+$bg1-a: $base1-a;
+$border: #28283d;
+$shadow: $crust;
diff --git a/home/.config/eww/css/modules/_battery.scss b/home/.config/eww/css/modules/_battery.scss
new file mode 100644
index 0000000..43f1062
--- /dev/null
+++ b/home/.config/eww/css/modules/_battery.scss
@@ -0,0 +1,46 @@
+@keyframes blink {
+ 0%{
+ opacity: 0;
+ }
+ 50%{
+ opacity: 0.7;
+ }
+ 100%{
+ opacity: 0;
+ }
+ }
+
+// .unplugged.low {
+// color: #0000ff;
+// }
+
+.battery {
+ .critical {
+ .unplugged {
+ color: #f00;
+ .extra { animation: blink 1.2s linear infinite; }
+ }
+
+ .plugged {
+ .icon { color: $orange }
+ .extra { color: $green; }
+ }
+ }
+
+ .normal {
+ .unplugged {
+ .icon { color: $orange }
+ }
+ .plugged {
+ .icon { color: $green; }
+ }
+ }
+
+ .full {
+ .icon { color: $green; }
+ .extra { color: $lime; }
+ }
+
+ .extra { margin-right: 5px; }
+ .icon { margin-right: 5px; }
+}
diff --git a/home/.config/eww/css/modules/_bitcoin.scss b/home/.config/eww/css/modules/_bitcoin.scss
new file mode 100644
index 0000000..82d5a61
--- /dev/null
+++ b/home/.config/eww/css/modules/_bitcoin.scss
@@ -0,0 +1,3 @@
+.bitcoin {
+ .icon { margin-right: 6px; color: $gold; }
+}
diff --git a/home/.config/eww/css/modules/_clock.scss b/home/.config/eww/css/modules/_clock.scss
new file mode 100644
index 0000000..98d9823
--- /dev/null
+++ b/home/.config/eww/css/modules/_clock.scss
@@ -0,0 +1,4 @@
+.clock {
+ // color: $sapphire;
+ .icon { margin-right: 6px; color: $sapphire; }
+}
diff --git a/home/.config/eww/css/modules/_cpu.scss b/home/.config/eww/css/modules/_cpu.scss
new file mode 100644
index 0000000..a183c58
--- /dev/null
+++ b/home/.config/eww/css/modules/_cpu.scss
@@ -0,0 +1,3 @@
+.cpu {
+ .icon { color: $lime; }
+}
diff --git a/home/.config/eww/css/modules/_kernel.scss b/home/.config/eww/css/modules/_kernel.scss
new file mode 100644
index 0000000..652a60d
--- /dev/null
+++ b/home/.config/eww/css/modules/_kernel.scss
@@ -0,0 +1,3 @@
+.kernel {
+ .icon { color: $lavender; }
+}
diff --git a/home/.config/eww/css/modules/_memory.scss b/home/.config/eww/css/modules/_memory.scss
new file mode 100644
index 0000000..37d8432
--- /dev/null
+++ b/home/.config/eww/css/modules/_memory.scss
@@ -0,0 +1,3 @@
+.memory {
+ .icon { color: $maroon; }
+}
diff --git a/home/.config/eww/css/modules/_uptime.scss b/home/.config/eww/css/modules/_uptime.scss
new file mode 100644
index 0000000..63b1353
--- /dev/null
+++ b/home/.config/eww/css/modules/_uptime.scss
@@ -0,0 +1,3 @@
+.uptime {
+ .icon { color: $green; }
+}
diff --git a/home/.config/eww/css/modules/_volume.scss b/home/.config/eww/css/modules/_volume.scss
new file mode 100644
index 0000000..7a94630
--- /dev/null
+++ b/home/.config/eww/css/modules/_volume.scss
@@ -0,0 +1,9 @@
+.volume {
+ .icon { color: $peach; }
+ .speaker {
+ .icon {
+ margin-left: 8px;
+ margin-right: 5px;
+ }
+ }
+}
diff --git a/home/.config/eww/css/modules/_workspaces.scss b/home/.config/eww/css/modules/_workspaces.scss
new file mode 100644
index 0000000..040ad77
--- /dev/null
+++ b/home/.config/eww/css/modules/_workspaces.scss
@@ -0,0 +1,26 @@
+.workspaces {
+ background-color: $bg1-a;
+ border-radius: 25px;
+
+ .value {
+ margin-left: 10px;
+ margin-right: 10px;
+ }
+
+ .focused {
+ // text-decoration: underline;
+ // text-decoration-color: red;
+ // text-decoration-style: double;
+ font-weight: 900;
+ // color: $sapphire;
+ color: #fff;
+ }
+
+ .active {
+ color: #bbb;
+ }
+
+ .inactive {
+ color: #555;
+ }
+}
diff --git a/home/.config/eww/css/windows/_calendar.scss b/home/.config/eww/css/windows/_calendar.scss
new file mode 100644
index 0000000..2aadfa3
--- /dev/null
+++ b/home/.config/eww/css/windows/_calendar.scss
@@ -0,0 +1,32 @@
+.calendar-win {
+ @include window;
+ background-color: $bg;
+ border: 1px solid $border;
+ color: $fg;
+ padding: .2em;
+}
+
+calendar {
+ padding: 5px;
+
+ :selected {
+ color: $mauve;
+ }
+
+ .header {
+ color: $subtext1;
+ }
+
+ .highlight {
+ color: $maroon;
+ font-weight: bold;
+ }
+
+ .button {
+ color: $sapphire;
+ }
+
+ :indeterminate {
+ color: $overlay0;
+ }
+}
diff --git a/home/.config/eww/eww.scss b/home/.config/eww/eww.scss
new file mode 100644
index 0000000..18be4bf
--- /dev/null
+++ b/home/.config/eww/eww.scss
@@ -0,0 +1,71 @@
+@import 'css/colors';
+
+@mixin rounding {
+ border-radius: 16px;
+}
+
+@mixin window {
+ border: 1px solid $border;
+ box-shadow: 0 2px 3px $shadow;
+ margin: 5px 5px 10px;
+ @include rounding;
+}
+
+* {
+ all: unset;
+ transition: 200ms ease;
+}
+
+@import "css/windows/calendar";
+@import "css/modules/clock";
+@import "css/modules/volume";
+@import "css/modules/bitcoin";
+@import "css/modules/cpu";
+@import "css/modules/memory";
+@import "css/modules/uptime";
+@import "css/modules/kernel";
+@import "css/modules/battery";
+@import "css/modules/workspaces";
+
+.bar {
+ background-color: $bg-a;
+ color: $fg;
+
+ font-family: "JetBrains Mono", "Font Awesome 6 Free";
+ // margin-right: 10px;
+
+ label {
+ font-size: 14px;
+ }
+
+ // TODO: Use ercentages (for some reason it fails now)
+ min-width: 1920px;
+ padding-right: 20px;
+ padding-left: 20px;
+}
+
+tooltip {
+ background: $bg;
+ border: 1px solid $border;
+ border-radius: 8px;
+
+ label {
+ font-size: 1rem;
+ }
+}
+
+.module { margin: 0 5px; }
+
+.separ {
+ color: $surface0;
+ font-size: 1.5rem;
+ padding-bottom: 2px;
+}
+
+scale trough {
+ background-color: $bg1-a;
+ border-radius: 24px;
+ margin: 0 1rem;
+ min-height: 10px;
+ min-width: 70px;
+}
diff --git a/home/.config/eww/eww.yuck b/home/.config/eww/eww.yuck
new file mode 100644
index 0000000..16d1b04
--- /dev/null
+++ b/home/.config/eww/eww.yuck
@@ -0,0 +1,73 @@
+(defvar terminal "alacritty -e")
+
+(include "./modules/clock.yuck")
+(include "./modules/volume.yuck")
+(include "./modules/bitcoin.yuck")
+(include "./modules/cpu.yuck")
+(include "./modules/memory.yuck")
+(include "./modules/uptime.yuck")
+; (include "./modules/kernel.yuck")
+(include "./modules/battery.yuck")
+(include "./modules/window_name.yuck")
+(include "./modules/workspaces.yuck")
+
+(include "./windows/calendar.yuck")
+
+(defwidget sep []
+ (label :class "separ module" :text "|"))
+
+(defwidget left []
+ (box
+ :space-evenly false
+ :halign "start"
+ (window_name_module)
+ ))
+
+(defwidget right []
+ (box
+ :space-evenly false
+ :halign "end"
+ ; (kernel_module)
+ ; (sep)
+ (volume_module)
+ (sep)
+ (battery_module)
+ (sep)
+ (bitcoin_module)
+ (sep)
+ (cpu_module)
+ (sep)
+ (memory_module)
+ (sep)
+ (uptime_module)
+ (sep)
+ (clock_module)
+ (sep)
+ (system-tray)
+ ))
+
+(defwidget center []
+ (box
+ :space-evenly false
+ :halign "center"
+ (workspaces_module)
+ ))
+
+(defwidget bar []
+ (centerbox
+ :class "bar"
+ :orientation "horizontal"
+ (left)
+ (center)
+ (right)))
+
+(defwindow bar
+ :monitor 0
+ :geometry (geometry :x "0%"
+ :y "0%"
+ :width: "100%"
+ :height "32px"
+ :anchor "top center")
+ :stacking "fg"
+ :exclusive true
+ (bar))
diff --git a/home/.config/eww/modules/battery.yuck b/home/.config/eww/modules/battery.yuck
new file mode 100644
index 0000000..c8f194b
--- /dev/null
+++ b/home/.config/eww/modules/battery.yuck
@@ -0,0 +1,29 @@
+(defpoll battery
+ :interval "2s"
+ :initial '{"percent":"0","plugged":"false","status":"N/A","capacity_icon":"","extra_icon":"","manufacturer":"N/A","model_name":"N/A","technology":"N/A","energy_now":"0","enerfy_full":"0","enerfy_full_design":"0","cycle_count":"0","critical":"false","full":"false"}'
+ `scripts/battery`)
+
+(defwidget battery_module []
+ (eventbox
+ :class "module battery"
+
+ (box
+ :class {battery.critical ? "critical" : battery.full ? "full" : "normal"}
+ (box
+ :space-evenly false
+ :class {battery.plugged ? "plugged" : "unplugged" }
+
+ (box
+ :class "icon"
+ :space-evenly false
+
+ (label
+ :class "extra"
+ :text {battery.extra_icon})
+ (label
+ :text {battery.capacity_icon}))
+ (label
+ :class "value"
+ :text "${battery.percent}%"
+ )
+ ))))
diff --git a/home/.config/eww/modules/bitcoin.yuck b/home/.config/eww/modules/bitcoin.yuck
new file mode 100644
index 0000000..6e5039e
--- /dev/null
+++ b/home/.config/eww/modules/bitcoin.yuck
@@ -0,0 +1,19 @@
+(defpoll bitcoin
+ :interval "5m"
+ :initial "$N/A"
+ `~/.local/bin/scripts/cli/bitcoin`)
+
+(defwidget bitcoin_module []
+ (eventbox
+ :onclick "~/.local/bin/scripts/cli/bitcoin | xargs -I_ ${EWW_CMD} update bitcoin=_"
+ :class "module bitcoin"
+
+ (box
+ :space-evenly false
+
+ (label
+ :class "icon"
+ :text "ﴑ")
+ (label :text {bitcoin}))
+ )
+)
diff --git a/home/.config/eww/modules/clock.yuck b/home/.config/eww/modules/clock.yuck
new file mode 100644
index 0000000..5a73b50
--- /dev/null
+++ b/home/.config/eww/modules/clock.yuck
@@ -0,0 +1,22 @@
+(defpoll time
+ :interval "5s"
+ :initial '{"date": "01 Jan", "hour": "00", "minute": "00", "day": "Monday"}'
+ `date +'{"date": "%d %b", "hour": "%H", "minute": "%M", "day": "%A"}'`)
+
+(defwidget clock_module []
+
+ (eventbox
+ :onclick "${EWW_CMD} open --toggle calendar"
+ :tooltip {time.day}
+ :class "module clock"
+
+ (box
+ :space-evenly false
+
+ (label
+ :class "icon"
+ :text "")
+ (label
+ :class "value"
+ :text "${time.date} ${time.hour}:${time.minute}"))
+ ))
diff --git a/home/.config/eww/modules/cpu.yuck b/home/.config/eww/modules/cpu.yuck
new file mode 100644
index 0000000..940ffb3
--- /dev/null
+++ b/home/.config/eww/modules/cpu.yuck
@@ -0,0 +1,15 @@
+(defwidget cpu_module []
+ (eventbox
+ :class "module cpu"
+
+ (box
+ :space-evenly false
+
+ (label
+ :class "icon"
+ :text " ")
+ (label
+ :class "value"
+ :text "${round(EWW_CPU.avg,2)}%"
+ )
+ )))
diff --git a/home/.config/eww/modules/kernel.yuck b/home/.config/eww/modules/kernel.yuck
new file mode 100644
index 0000000..b0561d4
--- /dev/null
+++ b/home/.config/eww/modules/kernel.yuck
@@ -0,0 +1,23 @@
+; TODO: Figure out how to store this one-time
+
+(defpoll kernel
+ :interval "10000h"
+ :initial 'N/A'
+ ; `uname -r | sed -r 's/(.+)-arch(.+)/\\1/'`
+ `uname -r`)
+
+(defwidget kernel_module []
+ (eventbox
+ :class "module kernel"
+
+ (box
+ :space-evenly false
+
+ (label
+ :class "icon"
+ :text " ")
+ (label
+ :class "value"
+ :text {kernel}
+ )
+ )))
diff --git a/home/.config/eww/modules/memory.yuck b/home/.config/eww/modules/memory.yuck
new file mode 100644
index 0000000..7c33074
--- /dev/null
+++ b/home/.config/eww/modules/memory.yuck
@@ -0,0 +1,15 @@
+(defwidget memory_module []
+ (eventbox
+ :class "module memory"
+
+ (box
+ :space-evenly false
+
+ (label
+ :class "icon"
+ :text " ")
+ (label
+ :class "value"
+ :text "${round(EWW_RAM.used_mem / 1000000,1)}G: ${round(EWW_RAM.used_mem_perc,0)}%"
+ )
+ )))
diff --git a/home/.config/eww/modules/nightlight.yuck b/home/.config/eww/modules/nightlight.yuck
new file mode 100644
index 0000000..fd2f2fe
--- /dev/null
+++ b/home/.config/eww/modules/nightlight.yuck
@@ -0,0 +1,3 @@
+(deflisten nightlight
+ :initial `{"running": false,"temperature": 0}`
+ `scripts/nightlight --state`)
diff --git a/home/.config/eww/modules/uptime.yuck b/home/.config/eww/modules/uptime.yuck
new file mode 100644
index 0000000..d05a306
--- /dev/null
+++ b/home/.config/eww/modules/uptime.yuck
@@ -0,0 +1,29 @@
+(defpoll uptime
+ :interval "1m"
+ :initial 'N/A'
+ `uptime -p | sed \\
+ -e 's/^up //' \\
+ -e 's/ years\\?,\\?/y/' \\
+ -e 's/ months\\?,\\?/m/' \\
+ -e 's/ weeks\\?,\\?/w/' \\
+ -e 's/ days\\?,\\?/d/' \\
+ -e 's/ hours\\?,\\?/h/' \\
+ -e 's/ minutes\\?,\\?/m/' \\
+ -e 's/ seconds\\?,\\?/s/' \\
+ | cut -d' ' -f-2`)
+
+(defwidget uptime_module []
+ (eventbox
+ :class "module uptime"
+
+ (box
+ :space-evenly false
+
+ (label
+ :class "icon"
+ :text " ")
+ (label
+ :class "value"
+ :text {uptime}
+ )
+ )))
diff --git a/home/.config/eww/modules/volume.yuck b/home/.config/eww/modules/volume.yuck
new file mode 100644
index 0000000..44b3496
--- /dev/null
+++ b/home/.config/eww/modules/volume.yuck
@@ -0,0 +1,44 @@
+(defvar mic_rev false)
+
+(deflisten volume
+ :initial '{ "speaker_vol": "100", "speaker_mute": false, "speaker_icon": "", "microphone_mute": false, "microphone_vol": "100", "microphone_icon": "" }'
+ `scripts/volume loop`)
+
+(defwidget volume_module []
+ (box
+ :class "module volume"
+ :space-evenly false
+
+ (eventbox
+ :onscroll "scripts/volume setvol SOURCE 0.5 {}"
+ :onclick "scripts/volume togglemute SOURCE"
+ :onrightclick "${terminal} pulsemixer &"
+ :onhover "${EWW_CMD} update mic_rev=true"
+ :onhoverlost "${EWW_CMD} update mic_rev=false"
+ :class "microphone"
+ (box
+ (label
+ :class "icon"
+ :text {volume.microphone_icon})
+ (label
+ :visible {mic_rev && !volume.microphone_mute}
+ :class "value"
+ :text "${volume.microphone_vol}%")
+ ))
+
+ (eventbox
+ :onscroll "scripts/volume setvol SINK 0.5 {}"
+ :onclick "scripts/volume togglemute SINK"
+ :onrightclick "${terminal} pulsemixer &"
+ :class "speaker"
+ (box
+ (label
+ :class "icon"
+ :text {volume.speaker_icon})
+ (label
+ :visible {!volume.speaker_mute}
+ :class "value"
+ :text "${volume.speaker_vol}%")
+ ))
+
+ ))
diff --git a/home/.config/eww/modules/window_name.yuck b/home/.config/eww/modules/window_name.yuck
new file mode 100644
index 0000000..af74d58
--- /dev/null
+++ b/home/.config/eww/modules/window_name.yuck
@@ -0,0 +1,15 @@
+(deflisten window_name
+ :initial `{"class":"","name":"","formatted_name":""}`
+ `scripts/window_name`)
+
+; Consider making the window name clickable, opening up a full window that's showing
+; the selected window details (class, unformatted name, and perhaps even more, like
+; xwayland status, ...)
+(defwidget window_name_module []
+ (box
+ :class "module window_name"
+
+ (label
+ :class "value"
+ :text "${window_name.formatted_name}")
+ ))
diff --git a/home/.config/eww/modules/workspaces.yuck b/home/.config/eww/modules/workspaces.yuck
new file mode 100644
index 0000000..cfbaf66
--- /dev/null
+++ b/home/.config/eww/modules/workspaces.yuck
@@ -0,0 +1,26 @@
+(deflisten workspaces
+ :initial `[{"id": 1,"name": "N/A","monitor": "N/A","windows": 1,"hasfullscreen": false,"lastwindow": "N/A","lastwindowtitle": "N/A","format_name": "N/A","active": true}]`
+ `scripts/workspaces --loop`)
+
+
+; (defwidget sep []
+; (label :class "separ module" :text "|"))
+
+
+; Consider making the window name clickable, opening up a full window that's showing
+; the selected window details (class, unformatted name, and perhaps even more, like
+; xwayland status, ...)
+(defwidget workspaces_module []
+ (box
+ :class "module workspaces"
+
+ (for workspace in workspaces
+ (eventbox
+ :class {workspace.active ? 'focused' : workspace.windows > 0 ? 'active' : 'inactive'}
+ :onclick `scripts/workspaces --switch ${workspace.id}`
+
+ (label
+ :class "value"
+ :text {workspace.format_name}))
+ )
+ ))
diff --git a/home/.config/eww/scripts/.flake8 b/home/.config/eww/scripts/.flake8
new file mode 100644
index 0000000..ce90fbd
--- /dev/null
+++ b/home/.config/eww/scripts/.flake8
@@ -0,0 +1,11 @@
+[flake8]
+max-line-length=119
+extend-ignore=E203
+extend-select=B902,B904
+exclude=.venv,.git,.cache
+ignore=
+ ANN002, # *args annotation
+ ANN003, # **kwargs annotation
+ ANN101, # self param annotation
+ ANN102, # cls param annotation
+ ANN204, # return type annotation for special methods
diff --git a/home/.config/eww/scripts/battery b/home/.config/eww/scripts/battery
new file mode 100755
index 0000000..3395c82
--- /dev/null
+++ b/home/.config/eww/scripts/battery
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+# shellcheck source=include
+source "./scripts/include"
+
+# $BATTERY and $ADAPTER env vars can be set manually, being the names of the
+# devices (in /sys/class/power_supply/) i.e. BATTERY=BAT0 ADAPTER=ADP0
+# or, if left unset, they will be automatically picked.
+
+CAPACITY_ICONS=("" "" "" "" "")
+CHARGING_ICON=""
+DISCHARGING_ICON=""
+FULL_ICON="" # Plugged in, but no longer charging (fully charged)
+CRITICAL_ICON=""
+CRITICAL_PERCENTAGE=15
+
+
+if [ -z "$BATTERY" ]; then
+ # shellcheck disable=SC2010
+ BATTERY="$(ls -t /sys/class/power_supply | grep "BAT" | head -n 1)"
+fi
+
+if [ -z "$ADAPTER" ]; then
+ # shellcheck disable=SC2010
+ ADAPTER="$(ls -t /sys/class/power_supply | grep "ADP" | head -n 1)"
+fi
+
+get_bat_info() {
+ cat /sys/class/power_supply/"$BATTERY"/"$1"
+}
+
+get_adp_info() {
+ cat /sys/class/power_supply/"$ADAPTER"/"$1"
+}
+
+manufacturer="$(get_bat_info manufacturer)"
+model_name="$(get_bat_info model_name)"
+technology="$(get_bat_info technology)"
+energy_now="$(get_bat_info energy_now)"
+energy_full="$(get_bat_info energy_full)"
+energy_full_design="$(get_bat_info energy_full_design)"
+cycle_count="$(get_bat_info cycle_count)"
+
+capacity="$(get_bat_info capacity)"
+status="$(get_bat_info status)"
+[ "$(get_adp_info online)" -eq 1 ] && adp_connected="true" || adp_connected="false"
+
+full="false"
+capacity_icon="$(pick_icon "$capacity" 0 100 "${CAPACITY_ICONS[@]}")"
+
+if [ "$status" = "Not charging" ] || [ "$status" = "Full" ] && [ "$adp_connected" = "true" ]; then
+ extra_icon="$FULL_ICON"
+ full="true"
+elif [ "$status" = "Discharging" ] && [ "$capacity" -le "$CRITICAL_PERCENTAGE" ]; then
+ extra_icon="$CRITICAL_ICON"
+elif [ "$status" = "Discharging" ]; then
+ extra_icon="$DISCHARGING_ICON"
+elif [ "$status" = "Charging" ]; then
+ extra_icon="$CHARGING_ICON"
+fi
+
+[ "$capacity" -le "$CRITICAL_PERCENTAGE" ] && critical="true" || critical="false"
+
+jq -n -c --monochrome-output \
+ --arg percent "$capacity" \
+ --arg plugged "$adp_connected" \
+ --arg status "$status" \
+ --arg capacity_icon "$capacity_icon" \
+ --arg extra_icon "$extra_icon" \
+ --arg manufacturer "$manufacturer" \
+ --arg model_name "$model_name" \
+ --arg technology "$technology" \
+ --arg energy_now "$energy_now" \
+ --arg energy_full "$energy_full" \
+ --arg energy_full_design "$energy_full_design" \
+ --arg cycle_count "$cycle_count" \
+ --arg critical "$critical" \
+ --arg full "$full" \
+ '$ARGS.named'
diff --git a/home/.config/eww/scripts/include b/home/.config/eww/scripts/include
new file mode 100755
index 0000000..34b5b99
--- /dev/null
+++ b/home/.config/eww/scripts/include
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# $1: Current number
+# $2: Range minimum
+# $3: Range maximum
+# $4-: Icons as individual arguments
+pick_icon() {
+ cur="$1"
+ min="$2"
+ max="$3"
+ shift 3
+ icons=( "$@" )
+
+ index="$(echo "($cur-$min)/(($max-$min)/${#icons[@]})" | bc)"
+
+ # Print the picked icon, handling overflows/underflows, i.e. if our index is <0 or >len(icons)
+ if [ "$index" -ge "${#icons[@]}" ]; then
+ index=-1
+ elif [ "$index" -lt 0 ]; then
+ index=0
+ fi
+
+ echo "${icons[index]}"
+}
+
+# Will block and listen to the hyprland socket messages and output them
+# Generally used like: hyprland_ipc | while read line; do handle $line; done
+# Read for output format and available events
+# Note: requires openbsd version of netcat.
+# $1 - Optional event to listen for (no event filtering will be done if not provided)
+hyprland_ipc() {
+ if [ -z "$HYPRLAND_INSTANCE_SIGNATURE" ]; then
+ >&2 echo "Hyprland is not running, IPC not available"
+ exit 1
+ fi
+
+ SOCKET_PATH="/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
+
+ if [ -z "$1" ]; then
+ nc -U "$SOCKET_PATH" | while read -r test; do
+ echo "$test"
+ done
+ else
+ nc -U "$SOCKET_PATH" | while read -r test; do
+ # shellcheck disable=SC2016
+ echo "$test" | grep --line-buffered -E "^$1>>" | stdbuf -oL awk -F '>>' '{print $2}'
+ done
+ fi
+}
diff --git a/home/.config/eww/scripts/nightlight b/home/.config/eww/scripts/nightlight
new file mode 100644
index 0000000..f8e4c24
--- /dev/null
+++ b/home/.config/eww/scripts/nightlight
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# shellcheck source=include
+source "./scripts/include"
+
+# Consider usning a file as a flag for whether nightlight is on or off
+# as we might be in transition state and just killing the program might
+# not be enough.
+
+
+if [ "$1" = "toggle" ]; then
+ gammastep -x
+fi
diff --git a/home/.config/eww/scripts/pyproject.toml b/home/.config/eww/scripts/pyproject.toml
new file mode 100644
index 0000000..e3a2d4f
--- /dev/null
+++ b/home/.config/eww/scripts/pyproject.toml
@@ -0,0 +1,12 @@
+[tool.black]
+line-length = 119
+extend-exclude = "^/.cache"
+
+[tool.isort]
+profile = "black"
+line_length = 119
+atomic = true
+order_by_type = false
+case_sensitive = true
+combine_as_imports = true
+skip = [".venv", ".git", ".cache"]
diff --git a/home/.config/eww/scripts/storage b/home/.config/eww/scripts/storage
new file mode 100755
index 0000000..210e71c
--- /dev/null
+++ b/home/.config/eww/scripts/storage
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+MOUNTPOINTS=("/" "/mnt/ext")
+
+data="$(df -H)"
+
+as_json() {
+ mountpoint="$1"
+ res="$2"
+ arr_res=($res)
+
+ jq -n -c --monochrome-output \
+ --arg mountpoint "$mountpoint" \
+ --arg size "${arr_res[0]}" \
+ --arg used "${arr_res[1]}" \
+ --arg avail "${arr_res[2]}" \
+ --arg percent "${arr_res[3]}" \
+ '$ARGS.named'
+}
+
+output_json="[]"
+for mountpoint in "${MOUNTPOINTS[@]}"; do
+ res="$(echo "$data" | awk -v m="$mountpoint" '$6 == m {print $2 " " $3 " " $4 " " $5}')"
+ out="$(as_json "$mountpoint" "$res")"
+
+ # echo "$output_json $out" | jq -c -s
+
+ jq --argjson arr1 "$output_json" --argjson arr2 "[$out]" -n \
+'$arr1 + $arr2'
+
+ # mount_data+=("$mountpoint" $res)
+ # echo "${mount_data[@]}"
+done
+
+# echo "${mount_data[@]}"
diff --git a/home/.config/eww/scripts/temp b/home/.config/eww/scripts/temp
new file mode 100755
index 0000000..66262de
--- /dev/null
+++ b/home/.config/eww/scripts/temp
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# shellcheck source=include
+source "./scripts/include"
+
+hyprland_ipc "workspace|createworkspace|destroyworkspace"
diff --git a/home/.config/eww/scripts/volume b/home/.config/eww/scripts/volume
new file mode 100755
index 0000000..5d9b850
--- /dev/null
+++ b/home/.config/eww/scripts/volume
@@ -0,0 +1,114 @@
+#!/bin/bash
+
+# Define some icons
+SPEAKER_ICONS=("" "" "")
+SPEAKER_MUTED_ICON=""
+MIC_ICON=""
+MIC_MUTED_ICON=""
+
+# Define some helper functions for getting/setting audio data using wireplumber (wpctl)
+
+# $1 can either be "SINK" (speaker) or "SOURCE" (microphone)
+get_vol() {
+ wpctl get-volume "@DEFAULT_AUDIO_${1}@" | awk '{print int($2*100)}'
+}
+
+# $1 can either be "SINK" (speaker) or "SOURCE" (microphone)
+# #2 is the voulme (as percentage) to set the volume to
+# $3 is optional, if set, it can be '+' or '-', which then adds/decreases volume, instead of setting
+set_vol() {
+ wpctl set-volume "@DEFAULT_AUDIO_${1}@" "$(awk -v n="$2" 'BEGIN{print (n / 100)}')$3"
+}
+
+# $1 can either be "SINK" (speaker) or "SOURCE" (microphone)
+check_mute() {
+ wpctl get-volume "@DEFAULT_AUDIO_${1}@" | grep -i muted >/dev/null
+ echo $?
+}
+
+# $1 can either be "SINK" (speaker) or "SOURCE" (microphone)
+toggle_mute() {
+ wpctl set-mute "@DEFAULT_AUDIO_${1}@" toggle
+}
+
+get_report() {
+ spkr_vol="$(get_vol "SINK")"
+ mic_vol="$(get_vol "SOURCE")"
+
+ if [ "$(check_mute "SINK")" == "0" ]; then
+ spkr_mute="true"
+ spkr_icon="$SPEAKER_MUTED_ICON"
+ else
+ spkr_mute="false"
+ index="$(awk -v n="$spkr_vol" -v m="${#SPEAKER_ICONS[@]}" 'BEGIN{print int(n/(100/m))}')"
+
+ # We might end up with an higher than the length of icons, if the volume is over 100%
+ # in this case, set the index to last icon
+ if [ "$index" -ge "${#SPEAKER_ICONS[@]}" ]; then
+ spkr_icon="${SPEAKER_ICONS[-1]}"
+ else
+ spkr_icon="${SPEAKER_ICONS[$index]}"
+ fi
+ fi
+
+ if [ "$(check_mute "SOURCE")" = "0" ]; then
+ mic_mute="true"
+ mic_icon="$MIC_MUTED_ICON"
+ else
+ mic_mute="false"
+ mic_icon="$MIC_ICON"
+ fi
+
+ echo "{ \"speaker_vol\": \"$spkr_vol\", \"speaker_mute\": $spkr_mute, \"speaker_icon\": \"$spkr_icon\", \"microphone_mute\": $mic_mute, \"microphone_vol\": \"$mic_vol\", \"microphone_icon\": \"$mic_icon\" }"
+}
+
+# Continually run and report every volume change (into stdout)
+loop() {
+ pactl subscribe | grep --line-buffered "change" | while read -r _; do
+ get_report
+ done
+}
+
+case "$1" in
+ "loop")
+ get_report
+ loop
+ ;;
+
+ "once") get_report ;;
+
+ "togglemute")
+ if [ "$2" != "SOURCE" ] && [ "$2" != "SINK" ]; then
+ >&2 echo "Invalid usage, expected second argument to be 'SINK' or 'SOURCE', got '$2'"
+ exit 1
+ fi
+ toggle_mute "$2"
+ ;;
+
+ "setvol")
+ if [ "$2" != "SOURCE" ] && [ "$2" != "SINK" ]; then
+ >&2 echo "Invalid usage, expected second argument to be 'SINK' or 'SOURCE', got '$2'"
+ exit 1
+ fi
+
+ if [[ "$3" =~ ^[+-]?[0-9]*\.?[0-9]+$ ]]; then
+ case "$4" in
+ "") set_vol "$2" "$3" ;;
+ up|+) set_vol "$2" "$3" "+" ;;
+ down|-) set_vol "$2" "$3" "-" ;;
+ *)
+ >&2 echo "Invalid usage, expected fourth argument to be up/down or +/-, got '$4'"
+ exit 1
+ ;;
+ esac
+ else
+ >&2 echo "Invalid usage, exepcted third argument to be a number, got '$3'"
+ exit 1
+ fi
+ ;;
+
+ *)
+ >&2 echo "Invalid usage, argument '$1' not recognized."
+ exit 1
+ ;;
+esac
diff --git a/home/.config/eww/scripts/window_name b/home/.config/eww/scripts/window_name
new file mode 100755
index 0000000..b828326
--- /dev/null
+++ b/home/.config/eww/scripts/window_name
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+# shellcheck source=include
+source "./scripts/include"
+
+hyprland_ipc "activewindow" | ./scripts/window_name.py
diff --git a/home/.config/eww/scripts/window_name.py b/home/.config/eww/scripts/window_name.py
new file mode 100755
index 0000000..2603b0f
--- /dev/null
+++ b/home/.config/eww/scripts/window_name.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python3
+"""This is a utility script for regex remaps on window names.
+
+This is done in python, because of the complex regex logic, which would be pretty hard to
+recreate in bash. This python script is expected to be called from the bash script controlling
+the window names. Window name and class are obtained from piped stdin, to prevent having to
+needlessly keep restarting this program, which takes a while due to the interpreter starting
+overhead.
+"""
+import re
+import json
+import sys
+from typing import Iterator, Optional
+
+
+class RemapRule:
+ __slots__ = ("name_pattern", "output_pattern", "class_pattern")
+
+ def __init__(self, name_pattern: str, output_pattern: str, class_pattern: Optional[str] = None):
+ self.name_pattern = re.compile(name_pattern)
+ self.output_pattern = output_pattern
+ self.class_pattern = re.compile(class_pattern) if class_pattern else None
+
+ def apply(self, window_name: str, window_class: str) -> str:
+ """Returns new name after this remap rule was applied."""
+ if self.class_pattern is not None:
+ if not self.class_pattern.fullmatch(window_class):
+ # Rule doesn't apply, class mismatch, return original name
+ return window_name
+
+ res = self.name_pattern.fullmatch(window_name)
+ if not res:
+ # Rule doesn't apply, name mismatch, return original name
+ return window_name
+
+ # NOTE: This is potentially unsafe, since output_pattern might be say {0.__class__}, etc.
+ # meaning this allows arbitrary attribute access, however it doesn't allow running functions
+ # here. That said, code could still end up being run if there's some descriptor defined,
+ # and generally I wouldn't trust this in production. However, this code is for my personal
+ # use here, and all of the output patterns are hard-coded in this file, so in this case, it's
+ # fine. But if you see this code and you'd like to use it in your production code, maybe don't
+ return self.output_pattern.format(*res.groups())
+
+
+# Rules will be applied in specified order
+REMAP_RULES: list[RemapRule] = [
+ RemapRule(r"", "", ""),
+ RemapRule(r"(.*) — Mozilla Firefox", " {}", "firefox"),
+ RemapRule(r"Mozilla Firefox", " Mozilla Firefox", "firefox"),
+ RemapRule(r"Alacritty", " Alacritty", "Alacritty"),
+ RemapRule(r"zsh;#toggleterm#1 - \(term:\/\/(.+)\/\/(\d+):(.+)\) - N?VIM", " Terminal: {0}"),
+ RemapRule(r"(.+) \+ \((.+)\) - N?VIM", " {0} ({1}) [MODIFIED]"),
+ RemapRule(r"(.+) \((.+)\) - N?VIM", " {0} ({1})"),
+ RemapRule(r"(?:\[\d+\] )?\*?WebCord - (.+)", " {}", "WebCord"),
+ RemapRule(r"(.+) - mpv", " {}", "mpv"),
+ RemapRule(r"Stremio - (.+)", " Stremio - {}", "com.stremio.stremio"),
+ RemapRule(r"Spotify", " Spotify", "Spotify"),
+ RemapRule(r"pulsemixer", " Pulsemixer"),
+ RemapRule(r"(.*)", " {}", "Pcmanfm"),
+]
+
+MAX_LENGTH = 65
+
+
+def iter_window() -> Iterator[tuple[str, str]]:
+ """Listen for the window parameters from stdin/pipe, yields (window_name, window_class)."""
+ for line in sys.stdin:
+ line = line.removesuffix("\n")
+ els = line.split(",", maxsplit=1)
+ if len(els) != 2:
+ raise ValueError(f"Expected 2 arguments from stdin line (name, class), but got {len(els)}")
+ yield els[1], els[0]
+
+
+def main() -> None:
+ for window_name, window_class in iter_window():
+ formatted_name = window_name
+ for remap_rule in REMAP_RULES:
+ formatted_name = remap_rule.apply(formatted_name, window_class)
+
+ if len(formatted_name) > MAX_LENGTH:
+ formatted_name = formatted_name[:MAX_LENGTH - 3] + "..."
+
+ ret = json.dumps({"name": window_name, "class": window_class, "formatted_name": formatted_name})
+ print(ret)
+ sys.stdout.flush()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/home/.config/eww/scripts/workspaces b/home/.config/eww/scripts/workspaces
new file mode 100755
index 0000000..0562b10
--- /dev/null
+++ b/home/.config/eww/scripts/workspaces
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# shellcheck source=include
+source "./scripts/include"
+
+if [ "$1" = "--switch" ]; then
+ hyprctl dispatch workspace "$2" >/dev/null
+elif [ "$1" = "--loop" ]; then
+ hyprland_ipc "workspace|createworkspace|destroyworkspace" | ./scripts/workspaces.py "$@"
+else
+ ./scripts/workspaces.py "$@"
+fi
diff --git a/home/.config/eww/scripts/workspaces.py b/home/.config/eww/scripts/workspaces.py
new file mode 100755
index 0000000..6f3fb58
--- /dev/null
+++ b/home/.config/eww/scripts/workspaces.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python3
+import argparse
+import json
+import subprocess
+import sys
+from typing import TypedDict, TYPE_CHECKING
+
+if TYPE_CHECKING:
+ from _typeshed import SupportsRichComparison
+
+
+class WorkspaceInfo(TypedDict):
+ id: int
+ name: str
+ monitor: str
+ windows: int
+ hasfullscreen: bool
+ lastwindow: str
+ lastwindowtitle: str
+
+
+class ActiveWorkspaceInfo(TypedDict):
+ id: int
+ name: str
+
+
+class MonitorInfo(TypedDict):
+ id: int
+ name: str
+ description: str
+ width: int
+ height: int
+ refreshRate: float
+ x: int
+ y: int
+ activeWorkspace: ActiveWorkspaceInfo
+ reserved: list[int]
+ scale: float
+ transform: int
+ focused: bool
+ dpmsStatus: bool
+
+
+class OutputWorkspaceInfo(WorkspaceInfo):
+ format_name: str
+ active: bool
+
+
+# workspace id -> remapped name
+REMAPS = {
+ 1: "",
+ 2: "",
+ 3: "",
+ 4: "",
+ 5: "",
+ 6: "",
+ 7: "7",
+ 8: "8",
+ 9: "9",
+}
+
+# Skip the special (scratchpad) workspace
+SKIP = {-99}
+
+
+def workspace_sort(obj: OutputWorkspaceInfo) -> "SupportsRichComparison":
+ """Returns a key to sort by, given the current element."""
+ return obj["id"]
+
+
+def fill_blank_workspaces(open: list[OutputWorkspaceInfo]) -> list[OutputWorkspaceInfo]:
+ """Add in the rest of the workspaces which don't have any open windows on them.
+
+ This is needed because hyprland deletes workspaces with nothing in them.
+ Note that this assumes all available workspaces were listed in REMAPS, and will
+ only fill those. These blank workspaces will have most string values set to "N/A",
+ and most int values set to 0.
+ """
+ # Work on a copy, we don't want to alter the original list
+ lst = open.copy()
+
+ for remap_id, format_name in REMAPS.items():
+ # Skip for already present workspaces
+ if any(ws_info["id"] == remap_id for ws_info in lst):
+ continue
+
+ blank_ws: OutputWorkspaceInfo = {
+ "id": remap_id,
+ "name": str(remap_id),
+ "monitor": "N/A",
+ "windows": 0,
+ "hasfullscreen": False,
+ "lastwindow": "N/A",
+ "lastwindowtitle": "N/A",
+ "active": False,
+ "format_name": format_name,
+ }
+ lst.append(blank_ws)
+
+ return lst
+
+
+def get_workspaces() -> list[OutputWorkspaceInfo]:
+ """Obtain workspaces from hyprctl, sort them and add format_name arg."""
+ proc = subprocess.run(["hyprctl", "workspaces", "-j"], stdout=subprocess.PIPE)
+ proc.check_returncode()
+ workspaces: list[WorkspaceInfo] = json.loads(proc.stdout)
+
+ proc = subprocess.run(["hyprctl", "monitors", "-j"], stdout=subprocess.PIPE)
+ proc.check_returncode()
+ monitors: list[MonitorInfo] = json.loads(proc.stdout)
+
+ active_workspaces = {monitor["activeWorkspace"]["id"] for monitor in monitors}
+
+ out: list[OutputWorkspaceInfo] = []
+ for workspace in workspaces:
+ if workspace["id"] in SKIP:
+ continue
+ format_name = REMAPS.get(workspace["id"], workspace["name"])
+ active = workspace["id"] in active_workspaces
+ out.append({**workspace, "format_name": format_name, "active": active})
+
+ out = fill_blank_workspaces(out)
+ out.sort(key=workspace_sort)
+ return out
+
+
+def print_workspaces() -> None:
+ wks = get_workspaces()
+ ret = json.dumps(wks)
+ print(ret)
+ sys.stdout.flush()
+
+
+def main() -> None:
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--oneshot",
+ action="store_true",
+ help="Don't listen to stdout for updates, only run once and quit",
+ )
+ parser.add_argument(
+ "--loop",
+ action="store_true",
+ help="Listen to stdout input, once something is received, re-print workspaces"
+ )
+ args = parser.parse_args()
+
+ if args.loop and args.oneshot:
+ print("Can't use both --oneshot and --loop", file=sys.stdout)
+ sys.exit(1)
+
+ if args.loop is None and args.oneshot is None:
+ print("No option specified!", file=sys.stdout)
+ sys.exit(1)
+
+ # Print workspaces here immediately, we don't want to have to wait for the first
+ # update from stdin as we only receive those on actual workspace change.
+ print_workspaces()
+
+ if args.oneshot:
+ # We've already printed the workspaces once, we can exit now
+ return
+
+ # Reprint workspaces on each stdin update (flush)
+ for _ in sys.stdin:
+ print_workspaces()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/home/.config/eww/windows/calendar.yuck b/home/.config/eww/windows/calendar.yuck
new file mode 100644
index 0000000..610f00a
--- /dev/null
+++ b/home/.config/eww/windows/calendar.yuck
@@ -0,0 +1,14 @@
+(defwidget calendar-win []
+ (box
+ :class "calendar-win"
+ (calendar)))
+
+(defwindow calendar
+ :monitor 0
+ :geometry (geometry
+ :x "0%"
+ :y "0%"
+ :anchor "top right"
+ :width "0px"
+ :height "0px")
+ (calendar-win))
diff --git a/home/.config/git/config b/home/.config/git/config
new file mode 100644
index 0000000..d3421e3
--- /dev/null
+++ b/home/.config/git/config
@@ -0,0 +1,87 @@
+[user]
+ name = ItsDrike
+ email = itsdrike@protonmail.com
+ signingkey = B014E761034AF742
+[alias]
+ quickclone = "clone --single-branch --depth=1"
+ bareclone = "!sh -c 'git clone --bare \"$0\" \"$1\"/.bare; echo \"gitdir: ./.bare\" > \"$1/.git\"'"
+ bareinit = "!sh -c 'git init --bare \"$0\"/.bare; echo \"gitdir: ./.bare\" > \"$0/.git\"'"
+ cleanup = "!default_branch=$(git remote show origin | awk '/HEAD branch/ {print $NF}'); git remote prune origin && git checkout -q $default_branch && git for-each-ref refs/heads/ '--format=%(refname:short)' | while read branch; do mergeBase=$(git merge-base $default_branch $branch) && [[ $(git cherry $default_branch $(git commit-tree $(git rev-parse $branch^{tree}) -p $mergeBase -m _)) == '-'* ]] && git branch -D $branch; done"
+
+ m = "merge"
+ p = "push"
+ pl = "pull"
+ f = "fetch"
+
+ s = "status --short --branch"
+ ss = "status"
+
+ ch = "checkout"
+ chb = "checkout -b"
+
+ undo = "reset --soft HEAD~"
+ redo = "reset HEAD@{1}"
+ unstage = "restore --staged"
+
+ c = "commit"
+ ca = "commit --ammend"
+ ci = "commit --interactive"
+ cm = "commit --message"
+ cv = "commit --verbose"
+
+ a = "add"
+ aa = "add --all"
+ ap = "add --patch"
+ au = "add --update"
+
+ d = "diff"
+ dc = "diff --cached"
+ ds = "diff --staged"
+ dw = "diff --word-diff"
+ dcm = "!sh -c 'git diff $0~ $0'"
+
+ b = "branch"
+ ba = "branch --all"
+ bd = "branch --delete"
+ bD = "branch --delete --force"
+ bm = "branch --move"
+ bM = "branch --move --force"
+
+ r = "rebase"
+ ri = "rebase -i"
+ rc = "rebase --continue"
+
+ l = "log --oneline --decorate --all --graph"
+ lp = "log --patch"
+ lo = "log --pretty=oneline --abbrev-commit --graph"
+ lg = "log --all --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --"
+
+ set-upstream = "!git branch --set-upstream-to=origin/`git symbolic-ref --short HEAD`"
+
+ stash-staged = "!sh -c 'git stash --keep-index; git stash push -m \"staged\" --keep-index; git stash pop stash@{1}'"
+
+ find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
+ show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"
+
+ comitter-lines = "!git log --author=\"$1\" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf \"added lines: %s, removed lines: %s, total lines: %s\\n\", add, subs, loc }' #"
+ total-lines = "!git ls-files | xargs cat | wc -l"
+[credential]
+ helper = store --file ~/.config/git/git-credentials
+[core]
+ excludefile = ~/.config/git/global_gitignore
+ editor = lvim
+ pager = delta
+[interactive]
+ diffFilter = delta --color-only
+[delta]
+ line-numbers = true
+[merge]
+ conflictstyle = diff3
+[diff]
+ tool = vimdiff
+[fetch]
+ prune = true
+[commit]
+ gpgsign = true
+[init]
+ defaultBranch = main
diff --git a/home/.config/git/global_gitignore b/home/.config/git/global_gitignore
new file mode 100644
index 0000000..366035c
--- /dev/null
+++ b/home/.config/git/global_gitignore
@@ -0,0 +1,25 @@
+# vim: filetype=conf
+# Byte-compiled / optimized / DLL Files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# Virtual Environments
+.venv/
+
+# Editor project settings
+## VSCode
+.vscode/
+## PyCharm intellij
+.idea/
+## repl.it
+.replit
+## spyder
+.spyproject/
+.spyderproject/
+
+# Custom attributes for folders on Mac OS
+.DS_Store
+
+# Personal TODO files
+TODO
diff --git a/home/.config/gtk-2.0/gtkfilechooser.ini b/home/.config/gtk-2.0/gtkfilechooser.ini
new file mode 100644
index 0000000..6171c6a
--- /dev/null
+++ b/home/.config/gtk-2.0/gtkfilechooser.ini
@@ -0,0 +1,11 @@
+[Filechooser Settings]
+LocationMode=path-bar
+ShowHidden=false
+ShowSizeColumn=true
+GeometryX=510
+GeometryY=260
+GeometryWidth=900
+GeometryHeight=584
+SortColumn=name
+SortOrder=ascending
+StartupMode=recent
diff --git a/home/.config/gtk-2.0/gtkrc b/home/.config/gtk-2.0/gtkrc
new file mode 100644
index 0000000..7348f1a
--- /dev/null
+++ b/home/.config/gtk-2.0/gtkrc
@@ -0,0 +1,19 @@
+# DO NOT EDIT! This file will be overwritten by LXAppearance.
+# Any customization should be done in ~/.gtkrc-2.0.mine instead.
+
+include "/home/itsdrike/.gtkrc-2.0.mine"
+gtk-theme-name="Adwaita-dark"
+gtk-icon-theme-name="Papirus-Dark"
+gtk-font-name="Noto Sans, 10"
+gtk-cursor-theme-name="BreezeX-Light"
+gtk-cursor-theme-size=24
+gtk-toolbar-style=GTK_TOOLBAR_BOTH_HORIZ
+gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
+gtk-button-images=1
+gtk-menu-images=1
+gtk-enable-event-sounds=1
+gtk-enable-input-feedback-sounds=1
+gtk-xft-antialias=1
+gtk-xft-hinting=1
+gtk-xft-hintstyle="hintfull"
+gtk-modules="colorreload-gtk-module:window-decorations-gtk-module:appmenu-gtk-module"
diff --git a/home/.config/gtk-3.0/bookmarks b/home/.config/gtk-3.0/bookmarks
new file mode 100644
index 0000000..4539c36
--- /dev/null
+++ b/home/.config/gtk-3.0/bookmarks
@@ -0,0 +1,3 @@
+file:///home/itsdrike/Pictures Pictures
+file:///home/itsdrike/Downloads Downloads
+file:///home/itsdrike/Personal Personal
diff --git a/home/.config/gtk-3.0/settings.ini b/home/.config/gtk-3.0/settings.ini
new file mode 100644
index 0000000..629ebe3
--- /dev/null
+++ b/home/.config/gtk-3.0/settings.ini
@@ -0,0 +1,21 @@
+[Settings]
+gtk-application-prefer-dark-theme=true
+gtk-button-images=1
+gtk-cursor-theme-name=BreezeX-Light
+gtk-cursor-theme-size=24
+gtk-decoration-layout=icon:minimize,maximize,close
+gtk-enable-animations=true
+gtk-font-name=Noto Sans, 10
+gtk-icon-theme-name=Papirus-Dark
+gtk-menu-images=1
+gtk-modules=colorreload-gtk-module:window-decorations-gtk-module:appmenu-gtk-module
+gtk-primary-button-warps-slider=false
+gtk-shell-shows-menubar=1
+gtk-theme-name=Adwaita-dark
+gtk-toolbar-style=GTK_TOOLBAR_BOTH_HORIZ
+gtk-toolbar-icon-size=GTK_ICON_SIZE_LARGE_TOOLBAR
+gtk-enable-event-sounds=1
+gtk-enable-input-feedback-sounds=1
+gtk-xft-antialias=1
+gtk-xft-hinting=1
+gtk-xft-hintstyle=hintfull
diff --git a/home/.config/hypr/hyprland.conf b/home/.config/hypr/hyprland.conf
new file mode 100644
index 0000000..937272a
--- /dev/null
+++ b/home/.config/hypr/hyprland.conf
@@ -0,0 +1,204 @@
+# Should be configured per-profile
+monitor = eDP-1, preferred, auto, 1
+workspace = eDP-1, 1
+
+# Autostart
+exec-once = dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
+exec-once = systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
+exec-once = hypr-restart-portals
+
+exec-once = setbg
+# exec-once = waybar --config ~/.config/waybar/config-hypr >~/.waybar.txt 2>&1
+exec-once = dunst>
+exec-once = swayidle
+
+exec-once = nm-applet
+exec-once = aa-notify -p
+exec-once = udiskie -A -T
+
+exec-once = webcord --start-minimized
+
+
+input {
+ kb_layout = us, sk
+ kb_variant = ,qwerty
+ kb_options = grp:alt_shift_toggle
+ numlock_by_default=true
+
+ follow_mouse = 1
+
+ touchpad {
+ natural_scroll = no
+ }
+}
+
+general {
+ gaps_in = 5
+ gaps_out = 8
+ border_size = 2
+ #col.active_border = 0xFF327BD1 # blue
+ col.active_border = 0xFFFFA500 # orange
+ col.inactive_border = 0xFF000000 # black
+ layout = dwindle
+}
+
+decoration {
+ rounding = 8
+ blur = 1
+ blur_size = 3
+ blur_passes = 2
+ blur_new_optimizations = 1
+
+ drop_shadow = 1
+ shadow_ignore_window = 1
+ shadow_offset = 2 2
+ shadow_range = 4
+ shadow_render_power = 1
+ col.shadow = 0x55000000
+}
+
+animations {
+ enabled = 1
+ animation = windows, 1, 3, default, popin 50%
+ animation = border, 1, 4, default
+ animation = fade, 1, 4, default
+ animation = workspaces, 1, 3, default
+}
+
+dwindle {
+ pseudotile = 1
+ preserve_split = 1
+ no_gaps_when_only = 0
+}
+
+# Automatically move windows to their workspace
+windowrulev2 = workspace 2, class:^(firefox)$
+windowrulev2 = workspace 4, class:^(discord)$
+windowrulev2 = workspace 4, class:^(WebCord)$
+windowrulev2 = workspace 6, class:^(Stremio)$
+
+# Give apps proper size
+windowrulev2 = float, class:^(qalculate-gtk)$
+windowrulev2 = size 800 550, class:^(qalculate-gtk)$
+
+
+# Mouse window resizing
+bindm = SUPER, mouse:272, movewindow
+bindm = SUPER, mouse:273, resizewindow
+
+# Compositor commands
+bind = SUPER, Space, fullscreen,
+bind = SUPER, W, killactive,
+bind = SUPER, F, togglefloating,
+bind = SUPER, S, togglesplit,
+bind = SUPER, G, togglegroup,
+bind = SUPER_SHIFT, N, changegroupactive, f
+bind = SUPER_SHIFT, P, changegroupactive, b
+bind = SUPER, P, pseudo,
+bind = SUPER_SHIFT, Q, exit, # TODO: Use pkill and prompt for confirm
+
+# Utilities
+bind = SUPER_CTRL, L, exec, swaylock -fF
+bind = SUPER_SHIFT, L, exec, wlogout -p layer-shell
+
+# Programs
+bind = SUPER, Return, exec, alacritty
+bind = SUPER, X, exec, pcmanfm
+bind = SUPER, B, exec, firefox
+bind = SUPER, R, exec, wofi --show drun
+bind = SUPER_SHIFT, Return, exec, wofi --show run
+
+# Notifications
+bind = CTRL, grave, exec, dunstctl close
+bind = CTRL_SHIFT, grave, exec, dunstctl close-all
+bind = CTRL, period, exec, dunstctl history-pop
+bind = CTRL_SHIFT, period, exec, dunstctl context
+
+# Volume comtrol
+binde = SUPER, Down, exec, pulsemixer --change-volume -5
+binde = SUPER, Up, exec,pulsemixer --change-volume +5
+binde = , XF86AudioLowerVolume, exec, pulsemixer --change-volume -5
+binde = , XF86AudioRaiseVolume, exec, pulsemixer --change-volume +5
+bind = , XF86AudioMute, exec, pulsemixer --toggle-mute
+
+# Brightness control
+binde = SUPER, Right, exec, brightness -i 5% -n
+binde = SUPER, Left, exec, brightness -d 5% -n
+binde = , XF86MonBrightnessUp, exec, brightness -i 5% -n
+binde = , XF86MonBrightnessDown, exec, brightness -d 5% -n
+
+# Screenshots
+bind = ,Print, exec, grim -g "$(slurp)" - | wl-copy && notify-send "Screenshot" "Screenshot saved to clipboard"
+bind = SUPER, Print, exec, grim -g "$(slurp)" - | swappy -f - -o - | wl-copy
+bind = CTRL, Print, exec, echo "" | wofi --prompt "Set delay (ms)" --show dmenu | xargs -I _ sleep _e-3 && grim -g "$(slurp)" - | wl-copy
+bind = SUPER_CTRL, Print, exec, echo "" | wofi --prompt "Set delay (ms)" --show dmenu | xargs -I _ sleep _e-3 && grim -g "$(slurp)" - | swappy -f - -o - | wl-copy
+bind = SHIFT, Print, exec, wl-copy "$(hyprpicker)" && notify-send 'Picked color' "$(wl-paste) (saved to clipboard)"
+
+# Move between windows
+bind = SUPER, h, movefocus, l
+bind = SUPER, l, movefocus, r
+bind = SUPER, k, movefocus, u
+bind = SUPER, j, movefocus, d
+
+# Window resizing
+bind = SUPER, Q, submap, resize
+submap = resize
+binde = , right, resizeactive, 10 0
+binde = , left, resizeactive, -10 0
+binde = , up, resizeactive, 0 -10
+binde = , down, resizeactive, 0 10
+binde = , L, resizeactive, 10 0
+binde = , H, resizeactive, -10 0
+binde = , K, resizeactive, 0 -10
+binde = , J, resizeactive, 0 10
+bind = , escape, submap, reset
+bind = SUPER, Q, submap, reset
+submap = reset
+
+# Move between workspaces
+bind = SUPER, 1, workspace, 1
+bind = SUPER, 2, workspace, 2
+bind = SUPER, 3, workspace, 3
+bind = SUPER, 4, workspace, 4
+bind = SUPER, 5, workspace, 5
+bind = SUPER, 6, workspace, 6
+bind = SUPER, 7, workspace, 7
+bind = SUPER, 8, workspace, 8
+bind = SUPER, 9, workspace, 9
+
+# Move windows to workspaces
+bind = SUPER_SHIFT, 1, movetoworkspacesilent, 1
+bind = SUPER_SHIFT, 2, movetoworkspacesilent, 2
+bind = SUPER_SHIFT, 3, movetoworkspacesilent, 3
+bind = SUPER_SHIFT, 4, movetoworkspacesilent, 4
+bind = SUPER_SHIFT, 5, movetoworkspacesilent, 5
+bind = SUPER_SHIFT, 6, movetoworkspacesilent, 6
+bind = SUPER_SHIFT, 7, movetoworkspacesilent, 7
+bind = SUPER_SHIFT, 8, movetoworkspacesilent, 8
+bind = SUPER_SHIFT, 9, movetoworkspacesilent, 9
+
+
+# Move windows to workspaces and focus it there
+bind = ALT, 1, movetoworkspace, 1
+bind = ALT, 2, movetoworkspace, 2
+bind = ALT, 3, movetoworkspace, 3
+bind = ALT, 4, movetoworkspace, 4
+bind = ALT, 5, movetoworkspace, 5
+bind = ALT, 6, movetoworkspace, 6
+bind = ALT, 7, movetoworkspace, 7
+bind = ALT, 8, movetoworkspace, 8
+bind = ALT, 9, movetoworkspace, 9
+
+# Cycle workspaces
+bind = SUPER, mouse_down, workspace, m+1
+bind = SUPER, mouse_up, workspace, m-1
+bind = SUPER, bracketleft, workspace, m-1
+bind = SUPER, bracketright, workspace, m+1
+
+# Cycle monitors
+bind = SUPER_SHIFT, braceleft, focusmonitor, l
+bind = SUPER_SHIFT, braceright, focusmonitor, r
+
+# Special workspace
+bind = ALT, grave, movetoworkspace, special
+bind = SUPER, grave, togglespecialworkspace,
diff --git a/home/.config/java/.keep b/home/.config/java/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/home/.config/lf/clear_img.sh b/home/.config/lf/clear_img.sh
new file mode 100755
index 0000000..dbc35d7
--- /dev/null
+++ b/home/.config/lf/clear_img.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+readonly PREVIEW_ID="preview"
+
+printf '{"action": "remove", "identifier": "%s"}\n' "$PREVIEW_ID" > "$FIFO_UEBERZUG"
+
diff --git a/home/.config/lf/draw_img.sh b/home/.config/lf/draw_img.sh
new file mode 100755
index 0000000..1547ca0
--- /dev/null
+++ b/home/.config/lf/draw_img.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+path="$1"
+x="$2"
+y="$3"
+width="$4"
+height="$5"
+PREVIEW_ID="preview"
+
+if [ -n "$FIFO_UEBERZUG" ]; then
+ printf '{"action": "add", "identifier": "%s", "x": %d, "y": %d, "width": %d, "height": %d, "scaler": "contain", "scaling_position_x": 0.5, "scaling_position_y": 0.5, "path": "%s"}\n' \
+ "$PREVIEW_ID" "$x" "$y" "$width" "$height" "$path" > "$FIFO_UEBERZUG"
+else
+ # Ueberzug isn't avialable, try to use pixterm
+ if command -v pixterm > /dev/null; then
+ pixterm -s 2 -tr "$x" -tc "$width" "$path"
+ else
+ >&2 echo "ueberzug not running, pixterm fallback not found!"
+ exit 1
+ fi
+fi
diff --git a/home/.config/lf/lfrc b/home/.config/lf/lfrc
new file mode 100644
index 0000000..8857c5e
--- /dev/null
+++ b/home/.config/lf/lfrc
@@ -0,0 +1,144 @@
+# Basic settings
+set previewer ~/.config/lf/previewer.sh
+set cleaner ~/.config/lf/clear_img.sh
+set preview true
+set hidden true
+set drawbox true
+set icons true
+set ignorecase true
+set scrolloff 5
+
+# Use $EDITOR for text
+cmd open ${{
+ case $(file --mime-type "$f" -bL) in
+ text/*|application/json) $EDITOR "$f";;
+ *) devour xdg-open "$f" ;;
+ esac
+}}
+
+# File/Directory control functions
+cmd mkdir %{{
+ printf "Directory Name: "
+ read ans
+ mkdir $ans
+}}
+
+cmd mkfile %{{
+ printf "File Name: "
+ read ans
+ touch $ans
+}}
+
+cmd chmod %{{
+ printf "Mode Bits: "
+ read ans
+
+ for file in "$fx"; do
+ chmod $ans $file
+ done
+
+ lf -remote 'send reload'
+}}
+
+# Add z.lua functionality for easy autojumps
+cmd zlua %{{
+ printf "z.lua input: "
+ read ans
+
+ /usr/local/src/z.lua/z.lua $ans
+}}
+
+
+# Archive bindings
+cmd unarchive ${{
+ case "$f" in
+ *.zip) unzip "$f" ;;
+ *.tar.gz) tar -xzvf "$f" ;;
+ *.tar.bz2) tar -xjvf "$f" ;;
+ *.tar) tar -xvf "$f" ;;
+ *) echo "Unsuported format" ;;
+ esac
+}}
+
+cmd zip %zip -r "$f" "$f"
+cmd tar %tar cvf "$f.tar" "$f"
+cmd targz %tar cvzf "%f.tar.gz" "$f"
+cmd tarbz2 %tar cjvf "$f.tar.bz2" "$f"
+
+# Trash-cli bindings
+cmd trash ${{
+ files=$(printf "$fx" | tr '\n' ':')
+ while [ "$files" ]; do
+ # extract the substring from start of string up to delimeter.
+ # this is the first "element" of the string
+ file=${files%%:*}
+
+ trash-put "$(basename "$file")"
+ # if there's only one element left, set `files` to an empty string.
+ # this causes us to exit this `while` loop.
+ # else, we delete the first "element" of the string from files, and
+ # move onto the next.
+ if [ "$files" = "$file" ]; then
+ files=''
+ else
+ files="${files#*;}"
+ fi
+ done
+}}
+
+cmd clear_trash %trash-empty
+
+cmd restore_trash ${{
+ trash-restore
+}}
+
+# Bindings
+# Remove some defaults
+map m
+map n
+map "'"
+map '"'
+map d
+map c
+
+# Archive mappings
+map az zip
+map at tar
+map ag targz
+map au unarchive
+
+# Trash mappings
+map dd trash
+map tc clear_trash
+map tr restore_trash
+
+# Basic functions
+map . set hidden!
+map DD delete
+map p paste
+map x cut
+map y copy
+map open
+map md mkdir
+map mf mkfile
+map ch chmod
+map r rename
+map H top
+map L bottom
+map R reload
+map C clear
+map z zlua
+
+# Movement
+map gh cd ~
+map gc cd ~/.config
+map gl cd ~/.local
+map gs cd ~/.local/bin/scripts
+map gtr cd ~/.local/share/Trash/files
+map gE. cd /etc
+map gEp cd /etc/portage
+map gU. cd /usr
+map gUs cd /usr/share
+map gUl cd /usr/local
+map gM cd /mnt
+
diff --git a/home/.config/lf/previewer.sh b/home/.config/lf/previewer.sh
new file mode 100755
index 0000000..73784f3
--- /dev/null
+++ b/home/.config/lf/previewer.sh
@@ -0,0 +1,162 @@
+#!/bin/sh
+# This script handles showing file-previews within lf.
+
+# It can also show image previews using ueberzug, however
+# that requires lf to be started with a script that also starts
+# ueberzug alongside of it.
+# (In my dotfiles, this script is in '~/.local/bin/scripts/lfu')
+# Alternatively, we could also handle ANSI previews with pixterms
+# this will be in a pretty low quiality, but it will work without
+# ueberzug. To enable this, change PIXTERM_ENABLED to 1.
+# if both ueberzug and pixterm are enabled, ueberzug takes precedence.
+PIXTERM_ENABLED=1
+
+run_cmd() {
+ # Try to run given command, if it is installed.
+ # If it isn't try to fallback to text_handle,
+ # otherwise fail completely.
+ cmd="$1"
+ shift
+
+ if command -v "$cmd" > /dev/null; then
+ $cmd $@
+ else
+ # If we didn't found the requested command, check if
+ # the file is text-like and try to use the text_handle
+ # to show the preview, this may not be ideal for given
+ # file-format, but at least we won't fail.
+ case $(file --mime-type "$1" -bL) in
+ # TODO: Consider checking for UTF-8 formatting instead,
+ # or show previews for any file-type
+ text/*|application/json)
+ echo "@@PREVIEW FALLBACK: Using text handle, $cmd command not found!"
+ text_handle "$1"
+ ;;
+ *)
+ echo "@@PREVIEW ERROR: Preview failed, $cmd command not found!"
+ ;;
+ esac
+ fi
+}
+
+draw_image() {
+ # Draw passed image with use of given draw_script.
+ # If the image contains EXIF (metadata) orientation info,
+ # handle it and draw the rotated image.
+ draw_script="$1"
+ file="$2"
+ shift
+ shift
+
+ # Calculate where the image should be placed on the screen.
+ num=$(printf "%0.f\n" "`echo "$(tput cols) / 2" | bc`")
+ numb=$(printf "%0.f\n" "`echo "$(tput cols) - $num - 1" | bc`")
+ numc=$(printf "%0.f\n" "`echo "$(tput lines) - 2" | bc`")
+
+ # Handle EXIF (metadata) orientation.
+ exif_orientation="$(identify -format '%[EXIF:Orientation]\n' -- "$file")"
+ if [ -n "$exif_orientation" ] && [ "$exif_orientation" != 1 ]; then
+ # In case `convert` command isn't aviable, ignore EXIF rotation
+ if command -v convert > /dev/null; then
+ cache=$(mktemp /tmp/thumbcache.XXXXX)
+ convert -- "$file" -auto-orient "$cache"
+ $draw_script "$cache" $num 1 $numb $numc
+ else
+ $draw_script "$file" $num 1 $numb $numc
+ fi
+ else
+ $draw_script "$file" $num 1 $numb $numc
+ fi
+
+ # Exit with status code 1 to signal lf that the function
+ # should be re-ran next time instead of caching the result.
+ exit 1
+}
+
+media_handle() {
+ # Handle media type files (videos, photos). These types of
+ # files are usually not stored in any form of textually readable
+ # format and they require a special way of displaying them.
+ # This mostly uses ueberzug (if available) for this.
+
+ draw_script="${XDG_CONFIG_HOME:-$HOME/.config}/lf/draw_img.sh"
+ file="$1"
+ shift
+
+ # Set ENABLED=1 if ueberzug or pixterm is enabled
+ command -v pixterm > /dev/null && [ "$PIXTERM_ENABLED" = 1 ] && ENABLED=1
+ [ -n "$FIFO_UEBERZUG" ] && [ -f "$draw_script" ] && ENABLED=1
+
+ case "$file" in
+ *.bmp|*.jpg|*.jpeg|*.png|*.xpm)
+ if [ -n "$ENABLED" ]; then
+ draw_image $draw_script "$file"
+ else
+ echo "@@PREVIEW FALLBACK: Using mediainfo, ueberzug isn't available."
+ run_cmd mediainfo "$file"
+ fi
+ ;;
+ *.avi|*.mp4|*.wmv|*.dat|*.3gp|*.ogv|*.mkv|*.mpg|*.mpeg|*.vob|*.fl[icv]|*.m2v|\
+ *.mov|*.webm|*.ts|*.mts|*.m4v|*.r[am]|*.qt|*.divx)
+ if [ -n "$ENABLED" ]; then
+ cache="$(mktemp /tmp/thumbcache.XXXXX)"
+ ffmpegthumbnailer -i "$file" -o "$cache" -s 0
+ draw_image $draw_script "$cache"
+ else
+ echo "@@PREVIEW FALLBACK: Using exiftool, ueberzug isn't aviable."
+ run_cmd exiftool "$file"
+ fi
+ ;;
+ *.wav|*.mp3|*.flac|*.m4a|*.wma|*.ape|*.ac3|*.og[agx]|*.spx|*.opus|*.as[fx]|*.flac)
+ # These types can't make use of ueberzug easily, so simply use eixftool
+ run_cmd exiftool "$file"
+ ;;
+ *)
+ echo "@@PREVIEW FALLBACK: Unrecognized media file, falling back to text handle."
+ text_handle "$file"
+ ;;
+ esac
+}
+
+text_handle() {
+ # Handle all other formats as text and cat them
+ # if highlighting tools are aviable, try to use them
+ if command -v bat > /dev/null; then
+ num=$(printf "%0.f\n" "`echo "$(tput cols) / 2" | bc`")
+ numb=$(printf "%d\n" "`echo "$(tput cols) - $num - 3" | bc`")
+ bat -pp --color=always --wrap=character --terminal-width="$numb" "$1"
+ elif command -v highlight > /dev/null; then
+ highlight "$1" --out-format ansi --force
+ else
+ cat "$1"
+ fi
+}
+
+# Capture all directories at first, since they could
+# potentionally match one of the file case statements
+if [ -d "$1" ]; then
+ tree "$1" -La 1
+elif [ -f "$1" ]; then
+ case "$1" in
+ *.tgz|*.tar.gz) run_cmd tar tzf "$1";;
+ *.tar.bz2|*.tbz2) run_cmd tar tjf "$1";;
+ *.tar.txz|*.txz) run_cmd xz --list "$1";;
+ *.tar) run_cmd tar tf "$1";;
+ *.zip|*.jar|*.war|*.ear|*.oxt) run_cmd unzip -l "$1";;
+ *.rar) run_cmd unrar l "$1";;
+ *.7z) run_cmd 7z l "$1";;
+ *.iso) run_cmd iso-info --no-header -l "$1";;
+ *.o) run_cmd nm "$1" | less ;;
+ *.csv) cat "$1" | sed s/,/\\n/g ;;
+ *odt,*.ods,*.odp,*.sxw) run_cmd odt2txt "$1";;
+ *.doc) run_cmd catdoc "$1" ;;
+ *.docx) run_cmd docx2txt "$1" - ;;
+ *.torrent) run_cmd transmission-show "$1";;
+ *.pdf) run_cmd pdftotext "$1";;
+ *.wav|*.mp3|*.flac|*.m4a|*.wma|*.ape|*.ac3|*.og[agx]|*.spx|*.opus|*.as[fx]|*.flac|\
+ *.avi|*.mp4|*.wmv|*.dat|*.3gp|*.ogv|*.mkv|*.mpg|*.mpeg|*.vob|*.fl[icv]|*.m2v|*.mov|\
+ *.webm|*.ts|*.mts|*.m4v|*.r[am]|*.qt|*.divx|\
+ *.bmp|*.jpg|*.jpeg|*.png|*.xpm) media_handle "$1" ;;
+ *) text_handle "$1" ;;
+ esac
+fi
diff --git a/home/.config/lvim/.luacheckrc b/home/.config/lvim/.luacheckrc
new file mode 100644
index 0000000..089f44b
--- /dev/null
+++ b/home/.config/lvim/.luacheckrc
@@ -0,0 +1,43 @@
+-- vim: ft=lua tw=80
+
+stds.nvim = {
+ globals = {
+ "lvim",
+ vim = { fields = { "g" } },
+ "TERMINAL",
+ "USER",
+ "C",
+ "Config",
+ "WORKSPACE_PATH",
+ "JAVA_LS_EXECUTABLE",
+ "MUtils",
+ "USER_CONFIG_PATH",
+ os = { fields = { "capture" } },
+ },
+ read_globals = {
+ "jit",
+ "os",
+ "vim",
+ "join_paths",
+ "get_runtime_dir",
+ "get_config_dir",
+ "get_cache_dir",
+ "get_lvim_base_dir",
+ "require_clean",
+ },
+}
+
+std = "lua51+nvim"
+
+files["tests/*_spec.lua"].std = "lua51+nvim+busted"
+
+-- Don't report unused self arguments of methods.
+self = false
+
+-- Rerun tests only if their modification time changed.
+cache = true
+
+ignore = {
+ "631", -- max_line_length
+ "212/_.*", -- unused argument, for vars with "_" prefix
+}
diff --git a/home/.config/lvim/.stylua.toml b/home/.config/lvim/.stylua.toml
new file mode 100644
index 0000000..df96b7b
--- /dev/null
+++ b/home/.config/lvim/.stylua.toml
@@ -0,0 +1,6 @@
+column_width = 120
+line_endings = "Unix"
+indent_type = "Spaces"
+indent_width = 2
+quote_style = "AutoPreferDouble"
+no_call_parentheses = true
diff --git a/home/.config/lvim/after/ftplugin/python.lua b/home/.config/lvim/after/ftplugin/python.lua
new file mode 100644
index 0000000..8395fbb
--- /dev/null
+++ b/home/.config/lvim/after/ftplugin/python.lua
@@ -0,0 +1,2 @@
+local dap_install = require "dap-install"
+dap_install.config("python", {})
diff --git a/home/.config/lvim/config.lua b/home/.config/lvim/config.lua
new file mode 100644
index 0000000..152a91a
--- /dev/null
+++ b/home/.config/lvim/config.lua
@@ -0,0 +1,43 @@
+require "user.keys"
+require "user.abbreviations"
+require "user.lsp"
+require "user.autocmds"
+require "user.plugins"
+require "user.options"
+require "user.lualine"
+require "user.treesitter"
+
+-- TEMPORARY; Learn vim, the hard way
+-- vim.opt.mouse = {}
+-- lvim.keys.normal_mode[""] = ""
+-- lvim.keys.normal_mode[""] = ""
+-- lvim.keys.normal_mode[""] = ""
+-- lvim.keys.normal_mode[""] = ""
+-- lvim.keys.visual_mode[""] = ""
+-- lvim.keys.visual_mode[""] = ""
+-- lvim.keys.visual_mode[""] = ""
+-- lvim.keys.visual_mode[""] = ""
+-- lvim.keys.insert_mode[""] = ""
+-- lvim.keys.insert_mode[""] = ""
+-- lvim.keys.insert_mode[""] = ""
+-- lvim.keys.insert_mode[""] = ""
+
+
+-- general
+lvim.log.level = "warn"
+lvim.format_on_save = false
+lvim.colorscheme = "onedarker"
+-- to disable icons and use a minimalist setup, uncomment the following
+-- lvim.use_icons = false
+
+-- TODO: User Config for predefined plugins
+-- After changing plugin config exit and reopen LunarVim, Run :PackerInstall :PackerCompile
+lvim.builtin.dap.active = true
+lvim.builtin.notify.active = true
+lvim.builtin.terminal.active = true
+lvim.builtin.alpha.active = true
+lvim.builtin.alpha.mode = "dashboard"
+lvim.builtin.nvimtree.setup.view.side = "left"
+lvim.builtin.project.patterns = { ".git", ".svn" }
+lvim.builtin.bufferline.options.always_show_bufferline = true
+-- lvim.builtin.nvimtree.setup.renderer.icons.show.git = false
diff --git a/home/.config/lvim/ftdetect/apparmor.lua b/home/.config/lvim/ftdetect/apparmor.lua
new file mode 100644
index 0000000..c27f5b7
--- /dev/null
+++ b/home/.config/lvim/ftdetect/apparmor.lua
@@ -0,0 +1,11 @@
+local autocmd = vim.api.nvim_create_autocmd
+
+autocmd({ "BufNewFile", "BufRead" }, {
+ pattern = { "/etc/apparmor.d/*" },
+ command = "setfiletype apparmor"
+})
+
+autocmd({ "BufNewFile", "BufRead" }, {
+ pattern = { "/usr/share/apparmor/extra-profiles/*" },
+ command = "setfiletype apparmor"
+})
diff --git a/home/.config/lvim/ftdetect/axaml.lua b/home/.config/lvim/ftdetect/axaml.lua
new file mode 100644
index 0000000..1204c37
--- /dev/null
+++ b/home/.config/lvim/ftdetect/axaml.lua
@@ -0,0 +1,6 @@
+local autocmd = vim.api.nvim_create_autocmd
+
+autocmd({ "BufNewFile", "BufRead" }, {
+ pattern = { "*.axaml" },
+ command = "setfiletype xml"
+})
diff --git a/home/.config/lvim/lua/user/abbreviations.lua b/home/.config/lvim/lua/user/abbreviations.lua
new file mode 100644
index 0000000..658a51b
--- /dev/null
+++ b/home/.config/lvim/lua/user/abbreviations.lua
@@ -0,0 +1,30 @@
+-- Define an abbreviation
+local function abbrev(mode, input, result, reabbrev)
+ reabbrev = reabbrev or false
+ local command
+ if reabbrev then
+ command = mode .. "abbrev"
+ else
+ command = mode .. "noreabbrev"
+ end
+ vim.cmd(command .. " " .. input .. " " .. result)
+end
+
+-- In case I have caps on (don't judge me for using caps)
+abbrev("c", "Wq", "wq")
+abbrev("c", "wQ", "wq")
+abbrev("c", "WQ", "wq")
+abbrev("c", "WQ!", "wq")
+abbrev("c", "wQ!", "wq")
+abbrev("c", "Wq!", "wq")
+abbrev("c", "W", "w")
+abbrev("c", "W!", "w!")
+abbrev("c", "Q", "q!")
+abbrev("c", "Q!", "q!")
+abbrev("c", "Qall", "qall")
+abbrev("c", "Qall!", "qall")
+abbrev("c", "QALL", "qall")
+abbrev("c", "QALL!", "qall")
+
+-- Save file with sudo
+abbrev("c", "w!!", "w !sudo tee > /dev/null %")
diff --git a/home/.config/lvim/lua/user/autocmds.lua b/home/.config/lvim/lua/user/autocmds.lua
new file mode 100644
index 0000000..2c873a3
--- /dev/null
+++ b/home/.config/lvim/lua/user/autocmds.lua
@@ -0,0 +1,19 @@
+-- Autocommands (https://neovim.io/doc/user/autocmd.html)
+
+-- Delete all trailing whitespace on saving
+vim.api.nvim_create_autocmd("BufWritePre", { pattern = "*.py", command = [[%s/\s\+$//e]] })
+-- Set text wrap to 119 characters
+vim.api.nvim_create_autocmd("BufWinEnter", { pattern = "*.md", command = "setlocal tw=119" })
+-- Jump to last position when opening a file
+vim.api.nvim_create_autocmd("BufReadPost", {
+ pattern = "*",
+ command = [[if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif]],
+})
+-- Highlight current line number
+vim.api.nvim_create_autocmd("ColorScheme", { pattern = "*", command = "highlight CursorLine guibg=#2b2b2b" })
+vim.api.nvim_create_autocmd("ColorScheme", {
+ pattern = "*",
+ command = "highlight CursorLineNr guifg=#1f85de ctermfg=LightBlue",
+})
+-- Custom syntax definitions based on file extensions
+vim.api.nvim_create_autocmd("BufRead", { pattern = "*.axml", command = "set ft=xml" })
diff --git a/home/.config/lvim/lua/user/keys.lua b/home/.config/lvim/lua/user/keys.lua
new file mode 100644
index 0000000..d0b657e
--- /dev/null
+++ b/home/.config/lvim/lua/user/keys.lua
@@ -0,0 +1,118 @@
+-- keymappings [view all the defaults by pressing Lk]
+lvim.leader = "space"
+
+-- Common shortcuts
+lvim.keys.normal_mode[""] = ":w"
+lvim.keys.insert_mode[""] = ":wi"
+lvim.keys.normal_mode[""] = ":undo"
+lvim.keys.normal_mode[""] = ":redo"
+
+-- Moevements
+lvim.keys.normal_mode["H"] = "^"
+lvim.keys.normal_mode["L"] = "$"
+
+-- Moving through buffers
+lvim.keys.normal_mode[""] = ":BufferLineCycleNext"
+lvim.keys.normal_mode[""] = ":BufferLineCyclePrev"
+lvim.keys.normal_mode[""] = ":BufferLineMoveNext"
+lvim.keys.normal_mode[""] = ":BufferLineMovePrev"
+
+-- Opening various menus
+lvim.keys.normal_mode[""] = ":NvimTreeFindFileToggle"
+lvim.keys.normal_mode[""] = ":Lf"
+lvim.keys.normal_mode[""] = ":MinimapToggle"
+lvim.keys.normal_mode[""] = ":SymbolsOutline"
+
+-- Delete to void register
+lvim.keys.visual_mode[""] = '"_d'
+lvim.keys.normal_mode[""] = '"_d'
+lvim.keys.visual_mode[""] = '"_dP'
+lvim.keys.visual_mode["p"] = '"_dP'
+
+-- Remove highlight
+lvim.keys.normal_mode[""] = ":nohlsearch"
+
+-- Debugger
+lvim.keys.normal_mode[""] = ":DapToggleBreakpoint"
+lvim.keys.normal_mode[""] = ":DapContinue"
+lvim.keys.normal_mode[""] = ":DapToggleRepl"
+lvim.keys.normal_mode[""] = ":DapTerminate"
+lvim.keys.normal_mode[""] = ":DapStepOver"
+lvim.keys.normal_mode[""] = ":DapStepInto"
+lvim.keys.normal_mode[""] = ":DapStepOut"
+
+lvim.builtin.which_key.mappings["h"] = {
+ name = "+Hop",
+ w = { "HopWord", "Word" },
+ p = { "HopPattern", "Pattern" },
+ a = { "HopAnywhere", "Anywhere" },
+ v = { "HopVertical", "Vertical" },
+}
+
+-- Quick word replacing (use . for next word)
+lvim.keys.normal_mode["cn"] = "*``cgn"
+lvim.keys.normal_mode["cN"] = "*``cgN"
+
+-- Quick replace all
+vim.api.nvim_set_keymap("n", "", "", {
+ noremap = true,
+ callback = function()
+ vim.fn.inputsave()
+ local query = vim.fn.input "To replace: "
+
+ vim.fn.inputsave()
+ local answer = vim.fn.input("Replace text: ", query)
+ vim.api.nvim_command("%s/\\V" .. query:gsub("/", "\\/") .. "/" .. answer:gsub("/", "\\/") .. "/")
+ vim.fn.inputrestore()
+ vim.api.nvim_feedkeys("v", "n", false)
+ end,
+})
+vim.api.nvim_set_keymap("v", "", "", {
+ noremap = true,
+ callback = function()
+ local getselection = function()
+ return vim.fn.strcharpart(vim.fn.getline(vim.fn.line "."), vim.fn.min {
+ vim.fn.charcol ".",
+ vim.fn.charcol "v",
+ } - 1, vim.fn.abs(vim.fn.charcol "." - vim.fn.charcol "v") + 1)
+ end
+
+ local query = getselection()
+
+ vim.fn.inputsave()
+ local answer = vim.fn.input("Replace text: ", query)
+ vim.api.nvim_command("%s/\\V" .. query:gsub("/", "\\/") .. "/" .. answer:gsub("/", "\\/") .. "/")
+ vim.fn.inputrestore()
+ vim.api.nvim_feedkeys("v", "n", false)
+ end,
+})
+
+-- Change Telescope navigation to use j and k for navigation and n and p for history in both input and normal mode.
+-- we use protected-mode (pcall) just in case the plugin wasn't loaded yet.
+-- local _, actions = pcall(require, "telescope.actions")
+-- lvim.builtin.telescope.defaults.mappings = {
+-- -- for input mode
+-- i = {
+-- [""] = actions.move_selection_next,
+-- [""] = actions.move_selection_previous,
+-- [""] = actions.cycle_history_next,
+-- [""] = actions.cycle_history_prev,
+-- },
+-- -- for normal mode
+-- n = {
+-- [""] = actions.move_selection_next,
+-- [""] = actions.move_selection_previous,
+-- },
+-- }
+
+-- Use which-key to add extra bindings with the leader-key prefix
+-- lvim.builtin.which_key.mappings["P"] = { "Telescope projects", "Projects" }
+-- lvim.builtin.which_key.mappings["t"] = {
+-- name = "+Trouble",
+-- r = { "Trouble lsp_references", "References" },
+-- f = { "Trouble lsp_definitions", "Definitions" },
+-- d = { "Trouble document_diagnostics", "Diagnostics" },
+-- q = { "Trouble quickfix", "QuickFix" },
+-- l = { "Trouble loclist", "LocationList" },
+-- w = { "Trouble workspace_diagnostics", "Workspace Diagnostics" },
+-- }
diff --git a/home/.config/lvim/lua/user/lsp.lua b/home/.config/lvim/lua/user/lsp.lua
new file mode 100644
index 0000000..35eb228
--- /dev/null
+++ b/home/.config/lvim/lua/user/lsp.lua
@@ -0,0 +1,68 @@
+-- generic LSP settings
+
+-- -- make sure server will always be installed even if the server is in skipped_servers list
+-- lvim.lsp.installer.setup.ensure_installed = {
+-- "sumeko_lua",
+-- "jsonls",
+-- }
+-- -- change UI setting of `LspInstallInfo`
+-- -- see
+-- lvim.lsp.installer.setup.ui.check_outdated_servers_on_open = false
+-- lvim.lsp.installer.setup.ui.border = "rounded"
+-- lvim.lsp.installer.setup.ui.keymaps = {
+-- uninstall_server = "d",
+-- toggle_server_expand = "o",
+-- }
+
+-- ---@usage disable automatic installation of servers
+lvim.lsp.installer.setup.automatic_installation = false
+
+-- ---configure a server manually. !!Requires `:LvimCacheReset` to take effect!!
+-- ---see the full default list `:lua print(vim.inspect(lvim.lsp.automatic_configuration.skipped_servers))`
+-- vim.list_extend(lvim.lsp.automatic_configuration.skipped_servers, { "pyright" })
+-- local opts = {} -- check the lspconfig documentation for a list of all possible options
+-- require("lvim.lsp.manager").setup("pyright", opts)
+
+-- ---remove a server from the skipped list, e.g. eslint, or emmet_ls. !!Requires `:LvimCacheReset` to take effect!!
+-- ---`:LvimInfo` lists which server(s) are skipped for the current filetype
+-- lvim.lsp.automatic_configuration.skipped_servers = vim.tbl_filter(function(server)
+-- return server ~= "emmet_ls"
+-- end, lvim.lsp.automatic_configuration.skipped_servers)
+
+-- -- you can set a custom on_attach function that will be used for all the language servers
+-- -- See
+-- lvim.lsp.on_attach_callback = function(client, bufnr)
+-- local function buf_set_option(...)
+-- vim.api.nvim_buf_set_option(bufnr, ...)
+-- end
+-- --Enable completion triggered by
+-- buf_set_option("omnifunc", "v:lua.vim.lsp.omnifunc")
+-- end
+
+-- set a formatter, this will override the language server formatting capabilities (if it exists)
+lvim.format_on_save = false
+local formatters = require "lvim.lsp.null-ls.formatters"
+formatters.setup {
+ -- each formatter accepts a list of options identical to
+ -- https://github.com/jose-elias-alvarez/null-ls.nvim/blob/main/doc/BUILTINS.md#Configuration
+ { command = "black", filetypes = { "python" } },
+ { command = "isort", filetypes = { "python" } },
+ {
+ command = "prettier",
+ extra_args = { "--print-width", "100" },
+ filetypes = { "typescript", "typescriptreact" },
+ },
+ { command = "stylua", filetypes = { "lua" } },
+ -- { command = "rustfmt", filetypes = { "rust" } },
+}
+
+-- set additional linters
+local linters = require "lvim.lsp.null-ls.linters"
+linters.setup {
+ -- Each linter accepts a list of options identical to
+ -- https://github.com/jose-elias-alvarez/null-ls.nvim/blob/main/doc/BUILTINS.md#Configuration
+ { command = "flake8", filetypes = { "python" } },
+ { command = "shellcheck", extra_args = { "--severity", "warning" } },
+ { command = "codespell", filetypes = { "javascript", "python" } },
+ { command = "luacheck", filetypes = { "lua" } },
+}
diff --git a/home/.config/lvim/lua/user/lualine.lua b/home/.config/lvim/lua/user/lualine.lua
new file mode 100644
index 0000000..d3635c6
--- /dev/null
+++ b/home/.config/lvim/lua/user/lualine.lua
@@ -0,0 +1,3 @@
+-- Add location (row:col) to lualine
+local components = require "lvim.core.lualine.components"
+lvim.builtin.lualine.sections.lualine_z = { components.location }
diff --git a/home/.config/lvim/lua/user/options.lua b/home/.config/lvim/lua/user/options.lua
new file mode 100644
index 0000000..87c4cf2
--- /dev/null
+++ b/home/.config/lvim/lua/user/options.lua
@@ -0,0 +1,24 @@
+-- Show whitespaces
+vim.opt.list = true -- Enable showing characters like ,
+vim.opt.listchars = { tab = " ", trail = "·" } -- Specify which characters to show
+
+-- Theme options
+vim.opt.cursorline = true -- Highlight cursor line
+vim.opt.laststatus = 2 -- Always show status line
+vim.opt.relativenumber = true -- Use relative line numbers
+vim.opt.wrap = true -- Allow line wrapping
+
+-- Tab/Indent settings
+-- vim.opt.autoindent = true -- Enable automatic indenting
+-- vim.opt.expandtab = true -- Expand tabs into spaces
+-- vim.opt.tabstop = 2 -- Number of spaces a tab in file accounts for
+-- vim.opt.shiftwidth = 4 -- Indentation size for Tab
+-- vim.opt.softtabstop = 4 -- Tabs/Spaces interlop
+-- vim.opt.tabpagemax = 50 -- More tabs
+-- vim.opt.shiftround = true -- Always round indent to multiple of shiftwidth
+
+-- Enable syntax highlighting in fenced markdown code-blocks
+vim.g.markdown_fenced_languages = {"html", "javascript", "typescript", "css", "scss", "lua", "vim", "python"}
+
+-- Other
+vim.opt.shell = "/bin/sh"
diff --git a/home/.config/lvim/lua/user/plugins.lua b/home/.config/lvim/lua/user/plugins.lua
new file mode 100644
index 0000000..ef432f3
--- /dev/null
+++ b/home/.config/lvim/lua/user/plugins.lua
@@ -0,0 +1,101 @@
+-- Additional Plugins
+lvim.plugins = {
+ { "wakatime/vim-wakatime" },
+
+ -- LSP
+ {
+ -- Tree-like view for symbols in current file using LSP
+ "simrat39/symbols-outline.nvim",
+ config = function()
+ require("symbols-outline").setup {
+ width = 18,
+ autofold_depth = 1,
+ }
+ end,
+ },
+ {
+ -- Show function signature while typing
+ "ray-x/lsp_signature.nvim",
+ config = function()
+ require("lsp_signature").on_attach()
+ end,
+ event = "BufRead",
+ },
+
+ -- User interface
+ {
+ -- Code minimap for easy orientation in a longer file
+ "wfxr/minimap.vim",
+ run = "cargo install --locked code-minimap",
+ config = function()
+ vim.cmd "let g:minimap_width = 10"
+ end,
+ },
+ {
+ -- Integrated lf file manager
+ "ptzz/lf.vim",
+ config = function()
+ vim.g.lf_map_keys = 0
+ end,
+ requires = "voldikss/vim-floaterm",
+ },
+
+ -- Github copilot for code completion
+ {
+ "zbirenbaum/copilot.lua",
+ event = { "VimEnter" },
+ config = function()
+ vim.defer_fn(function()
+ require("copilot").setup()
+ end, 100)
+ end,
+ },
+ { "zbirenbaum/copilot-cmp", after = { "copilot.lua", "nvim-cmp" } },
+
+ --
+ { "jasonccox/vim-wayland-clipboard" },
+
+ -- Yuck.vim (eww configuration language support)
+ { "elkowar/yuck.vim" },
+
+ -- Treesitter
+ -- {
+ -- -- Colorize matching parenthesis using treesitter
+ -- "p00f/nvim-ts-rainbow",
+ -- },
+ {
+ -- Treesitter information shown directly in neovim
+ "nvim-treesitter/playground",
+ },
+ {
+ -- Alwats show class/function name we're in
+ "romgrk/nvim-treesitter-context",
+ config = function()
+ require("treesitter-context").setup {
+ enable = true, -- Enable this plugin (Can be enabled/disabled later via commands)
+ throttle = true, -- Throttles plugin updates (may improve performance)
+ max_lines = 0, -- How many lines the window should span. Values <= 0 mean no limit.
+ patterns = { -- Match patterns for TS nodes. These get wrapped to match at word boundaries.
+ -- For all filetypes
+ -- Note that setting an entry here replaces all other patterns for this entry.
+ -- By setting the 'default' entry below, you can control which nodes you want to
+ -- appear in the context window.
+ default = {
+ "class",
+ "function",
+ "method",
+ "while",
+ "for",
+ "if",
+ "switch",
+ "case",
+ },
+ },
+ }
+ end,
+ },
+}
+
+-- Register copilot as cmp source
+lvim.builtin.cmp.formatting.source_names["copilot"] = "(Copilot)"
+table.insert(lvim.builtin.cmp.sources, 1, { name = "copilot" })
diff --git a/home/.config/lvim/lua/user/treesitter.lua b/home/.config/lvim/lua/user/treesitter.lua
new file mode 100644
index 0000000..804e7e5
--- /dev/null
+++ b/home/.config/lvim/lua/user/treesitter.lua
@@ -0,0 +1,42 @@
+-- if you don't want all the parsers change this to a table of the ones you want
+lvim.builtin.treesitter.ensure_installed = {
+ "bash",
+ "c",
+ "javascript",
+ "json",
+ "lua",
+ "python",
+ "typescript",
+ "tsx",
+ "css",
+ "rust",
+ "java",
+ "yaml",
+}
+
+lvim.builtin.treesitter.ignore_install = {}
+lvim.builtin.treesitter.highlight.enabled = true
+-- lvim.builtin.treesitter.rainbow.enable = true
+
+local parser_config = require "nvim-treesitter.parsers".get_parser_configs()
+parser_config.apparmor = {
+ install_info = {
+ url = "~/Personal/Programming/GitHub/Other/tree-sitter-apparmor", -- local path or git repo
+ files = {"src/parser.c"},
+ -- optional entries:
+ branch = "main", -- default branch in case of git repo if different from master
+ generate_requires_npm = false, -- if stand-alone parser without npm dependencies
+ requires_generate_from_grammar = false, -- if folder contains pre-generated src/parser.c
+ },
+ filetype = "apparmor", -- if filetype does not match the parser name
+}
+
+local ft_to_parser = require"nvim-treesitter.parsers".filetype_to_parsername
+ft_to_parser.apparmor = "apparmor"
+
+-- Temporary treesitter
+lvim.keys.normal_mode["gu"] = ":TSUpdate apparmor"
+lvim.keys.normal_mode["gU"] = ":TSToggle apparmor"
+lvim.keys.normal_mode["gt"] = ":TSPlaygroundToggle"
+lvim.keys.normal_mode["gh"] = ":TSNodeUnderCursor"
+lvim.keys.normal_mode["gH"] = ":TSHighlightCapturesUnderCursor"
diff --git a/home/.config/lvim/plugin/packer_compiled.lua b/home/.config/lvim/plugin/packer_compiled.lua
new file mode 100644
index 0000000..5a101fa
--- /dev/null
+++ b/home/.config/lvim/plugin/packer_compiled.lua
@@ -0,0 +1,499 @@
+-- Automatically generated packer.nvim plugin loader code
+
+if vim.api.nvim_call_function('has', {'nvim-0.5'}) ~= 1 then
+ vim.api.nvim_command('echohl WarningMsg | echom "Invalid Neovim version for packer.nvim! | echohl None"')
+ return
+end
+
+vim.api.nvim_command('packadd packer.nvim')
+
+local no_errors, error_msg = pcall(function()
+
+_G._packer = _G._packer or {}
+_G._packer.inside_compile = true
+
+local time
+local profile_info
+local should_profile = false
+if should_profile then
+ local hrtime = vim.loop.hrtime
+ profile_info = {}
+ time = function(chunk, start)
+ if start then
+ profile_info[chunk] = hrtime()
+ else
+ profile_info[chunk] = (hrtime() - profile_info[chunk]) / 1e6
+ end
+ end
+else
+ time = function(chunk, start) end
+end
+
+local function save_profiles(threshold)
+ local sorted_times = {}
+ for chunk_name, time_taken in pairs(profile_info) do
+ sorted_times[#sorted_times + 1] = {chunk_name, time_taken}
+ end
+ table.sort(sorted_times, function(a, b) return a[2] > b[2] end)
+ local results = {}
+ for i, elem in ipairs(sorted_times) do
+ if not threshold or threshold and elem[2] > threshold then
+ results[i] = elem[1] .. ' took ' .. elem[2] .. 'ms'
+ end
+ end
+ if threshold then
+ table.insert(results, '(Only showing plugins that took longer than ' .. threshold .. ' ms ' .. 'to load)')
+ end
+
+ _G._packer.profile_output = results
+end
+
+time([[Luarocks path setup]], true)
+local package_path_str = "/home/itsdrike/.cache/lvim/packer_hererocks/2.1.0-beta3/share/lua/5.1/?.lua;/home/itsdrike/.cache/lvim/packer_hererocks/2.1.0-beta3/share/lua/5.1/?/init.lua;/home/itsdrike/.cache/lvim/packer_hererocks/2.1.0-beta3/lib/luarocks/rocks-5.1/?.lua;/home/itsdrike/.cache/lvim/packer_hererocks/2.1.0-beta3/lib/luarocks/rocks-5.1/?/init.lua"
+local install_cpath_pattern = "/home/itsdrike/.cache/lvim/packer_hererocks/2.1.0-beta3/lib/lua/5.1/?.so"
+if not string.find(package.path, package_path_str, 1, true) then
+ package.path = package.path .. ';' .. package_path_str
+end
+
+if not string.find(package.cpath, install_cpath_pattern, 1, true) then
+ package.cpath = package.cpath .. ';' .. install_cpath_pattern
+end
+
+time([[Luarocks path setup]], false)
+time([[try_loadstring definition]], true)
+local function try_loadstring(s, component, name)
+ local success, result = pcall(loadstring(s), name, _G.packer_plugins[name])
+ if not success then
+ vim.schedule(function()
+ vim.api.nvim_notify('packer.nvim: Error running ' .. component .. ' for ' .. name .. ': ' .. result, vim.log.levels.ERROR, {})
+ end)
+ end
+ return result
+end
+
+time([[try_loadstring definition]], false)
+time([[Defining packer_plugins]], true)
+_G.packer_plugins = {
+ ["Comment.nvim"] = {
+ config = { "\27LJ\2\n?\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\22lvim.core.comment\frequire\0" },
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/Comment.nvim",
+ url = "https://github.com/numToStr/Comment.nvim"
+ },
+ ["FixCursorHold.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/FixCursorHold.nvim",
+ url = "https://github.com/antoinemadec/FixCursorHold.nvim"
+ },
+ LuaSnip = {
+ config = { "\27LJ\2\n\3\0\0\v\0\23\00166\0\0\0'\2\1\0B\0\2\0024\1\0\0006\2\2\0009\2\3\0029\2\4\0029\2\5\0029\2\6\2\15\0\2\0X\3\f\21\2\1\0\22\2\0\0029\3\a\0006\5\b\0B\5\1\2'\6\t\0'\a\n\0'\b\v\0'\t\f\0'\n\r\0B\3\a\2<\3\2\0019\2\a\0006\4\14\0B\4\1\2'\5\15\0B\2\3\0029\3\16\0\18\5\2\0B\3\2\2\15\0\3\0X\4\3\21\3\1\0\22\3\0\3<\2\3\0016\3\0\0'\5\17\0B\3\2\0029\3\18\3B\3\1\0016\3\0\0'\5\19\0B\3\2\0029\3\18\0035\5\20\0=\1\21\5B\3\2\0016\3\0\0'\5\22\0B\3\2\0029\3\18\3B\3\1\1K\0\1\0\"luasnip.loaders.from_snipmate\npaths\1\0\0 luasnip.loaders.from_vscode\14lazy_load\29luasnip.loaders.from_lua\17is_directory\rsnippets\19get_config_dir\22friendly-snippets\nstart\vpacker\tpack\tsite\20get_runtime_dir\15join_paths\22friendly_snippets\fsources\fluasnip\fbuiltin\tlvim\15lvim.utils\frequire\2\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/LuaSnip",
+ url = "https://github.com/L3MON4D3/LuaSnip"
+ },
+ ["alpha-nvim"] = {
+ config = { "\27LJ\2\n=\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\20lvim.core.alpha\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/alpha-nvim",
+ url = "https://github.com/goolord/alpha-nvim"
+ },
+ ["bufferline.nvim"] = {
+ config = { "\27LJ\2\nB\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\25lvim.core.bufferline\frequire\0" },
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/bufferline.nvim",
+ url = "https://github.com/akinsho/bufferline.nvim"
+ },
+ ["cmp-buffer"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/cmp-buffer",
+ url = "https://github.com/hrsh7th/cmp-buffer"
+ },
+ ["cmp-nvim-lsp"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/cmp-nvim-lsp",
+ url = "https://github.com/hrsh7th/cmp-nvim-lsp"
+ },
+ ["cmp-path"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/cmp-path",
+ url = "https://github.com/hrsh7th/cmp-path"
+ },
+ cmp_luasnip = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/cmp_luasnip",
+ url = "https://github.com/saadparwaiz1/cmp_luasnip"
+ },
+ ["copilot-cmp"] = {
+ load_after = {
+ ["copilot.lua"] = true
+ },
+ loaded = false,
+ needs_bufread = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/copilot-cmp",
+ url = "https://github.com/zbirenbaum/copilot-cmp"
+ },
+ ["copilot.lua"] = {
+ after = { "copilot-cmp" },
+ config = { "\27LJ\2\n5\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\fcopilot\frequire-\1\0\4\0\3\0\0066\0\0\0009\0\1\0003\2\2\0)\3d\0B\0\3\1K\0\1\0\0\rdefer_fn\bvim\0" },
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/copilot.lua",
+ url = "https://github.com/zbirenbaum/copilot.lua"
+ },
+ ["dap-buddy.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/dap-buddy.nvim",
+ url = "https://github.com/Pocco81/dap-buddy.nvim"
+ },
+ ["friendly-snippets"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/friendly-snippets",
+ url = "https://github.com/rafamadriz/friendly-snippets"
+ },
+ ["gitsigns.nvim"] = {
+ config = { "\27LJ\2\n@\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\23lvim.core.gitsigns\frequire\0" },
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/gitsigns.nvim",
+ url = "https://github.com/lewis6991/gitsigns.nvim"
+ },
+ ["lf.vim"] = {
+ config = { "\27LJ\2\n-\0\0\2\0\3\0\0056\0\0\0009\0\1\0)\1\0\0=\1\2\0K\0\1\0\16lf_map_keys\6g\bvim\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/lf.vim",
+ url = "https://github.com/ptzz/lf.vim"
+ },
+ ["lsp_signature.nvim"] = {
+ config = { "\27LJ\2\n?\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\14on_attach\18lsp_signature\frequire\0" },
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/lsp_signature.nvim",
+ url = "https://github.com/ray-x/lsp_signature.nvim"
+ },
+ ["lua-dev.nvim"] = {
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/lua-dev.nvim",
+ url = "https://github.com/folke/lua-dev.nvim"
+ },
+ ["lualine.nvim"] = {
+ config = { "\27LJ\2\n?\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\22lvim.core.lualine\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/lualine.nvim",
+ url = "https://github.com/nvim-lualine/lualine.nvim"
+ },
+ ["mason-lspconfig.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/mason-lspconfig.nvim",
+ url = "https://github.com/williamboman/mason-lspconfig.nvim"
+ },
+ ["mason.nvim"] = {
+ config = { "\27LJ\2\n=\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\20lvim.core.mason\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/mason.nvim",
+ url = "https://github.com/williamboman/mason.nvim"
+ },
+ ["minimap.vim"] = {
+ config = { "\27LJ\2\n<\0\0\3\0\3\0\0056\0\0\0009\0\1\0'\2\2\0B\0\2\1K\0\1\0\29let g:minimap_width = 10\bcmd\bvim\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/minimap.vim",
+ url = "https://github.com/wfxr/minimap.vim"
+ },
+ ["nlsp-settings.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nlsp-settings.nvim",
+ url = "https://github.com/tamago324/nlsp-settings.nvim"
+ },
+ ["null-ls.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/null-ls.nvim",
+ url = "https://github.com/jose-elias-alvarez/null-ls.nvim"
+ },
+ ["nvim-autopairs"] = {
+ config = { "\27LJ\2\nA\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\24lvim.core.autopairs\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-autopairs",
+ url = "https://github.com/windwp/nvim-autopairs"
+ },
+ ["nvim-cmp"] = {
+ after = { "copilot-cmp" },
+ config = { "\27LJ\2\n`\0\0\3\0\6\0\v6\0\0\0009\0\1\0009\0\2\0\15\0\0\0X\1\56\0\3\0'\2\4\0B\0\2\0029\0\5\0B\0\1\1K\0\1\0\nsetup\18lvim.core.cmp\frequire\bcmp\fbuiltin\tlvim\0" },
+ loaded = true,
+ only_config = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-cmp",
+ url = "https://github.com/hrsh7th/nvim-cmp"
+ },
+ ["nvim-dap"] = {
+ config = { "\27LJ\2\n;\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\18lvim.core.dap\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-dap",
+ url = "https://github.com/mfussenegger/nvim-dap"
+ },
+ ["nvim-lspconfig"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-lspconfig",
+ url = "https://github.com/neovim/nvim-lspconfig"
+ },
+ ["nvim-notify"] = {
+ config = { "\27LJ\2\n>\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\21lvim.core.notify\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-notify",
+ url = "https://github.com/rcarriga/nvim-notify"
+ },
+ ["nvim-tree.lua"] = {
+ config = { "\27LJ\2\n@\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\23lvim.core.nvimtree\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-tree.lua",
+ url = "https://github.com/kyazdani42/nvim-tree.lua"
+ },
+ ["nvim-treesitter"] = {
+ config = { "\27LJ\2\nB\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\25lvim.core.treesitter\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-treesitter",
+ url = "https://github.com/nvim-treesitter/nvim-treesitter"
+ },
+ ["nvim-treesitter-context"] = {
+ config = { "\27LJ\2\n\1\0\0\5\0\b\0\v6\0\0\0'\2\1\0B\0\2\0029\0\2\0005\2\3\0005\3\5\0005\4\4\0=\4\6\3=\3\a\2B\0\2\1K\0\1\0\rpatterns\fdefault\1\0\0\1\t\0\0\nclass\rfunction\vmethod\nwhile\bfor\aif\vswitch\tcase\1\0\3\rthrottle\2\venable\2\14max_lines\3\0\nsetup\23treesitter-context\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-treesitter-context",
+ url = "https://github.com/romgrk/nvim-treesitter-context"
+ },
+ ["nvim-ts-context-commentstring"] = {
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/nvim-ts-context-commentstring",
+ url = "https://github.com/JoosepAlviste/nvim-ts-context-commentstring"
+ },
+ ["nvim-web-devicons"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/nvim-web-devicons",
+ url = "https://github.com/kyazdani42/nvim-web-devicons"
+ },
+ ["onedarker.nvim"] = {
+ config = { "\27LJ\2\n\1\0\0\3\0\t\0\0196\0\0\0\15\0\0\0X\1\156\0\0\0009\0\1\0\a\0\2\0X\0\v6\0\3\0'\2\2\0B\0\2\0029\0\4\0B\0\1\0016\0\0\0009\0\5\0009\0\6\0009\0\a\0'\1\2\0=\1\b\0K\0\1\0\ntheme\foptions\flualine\fbuiltin\nsetup\frequire\14onedarker\16colorscheme\tlvim\30\1\0\3\0\2\0\0046\0\0\0003\2\1\0B\0\2\1K\0\1\0\0\npcall\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/onedarker.nvim",
+ url = "https://github.com/lunarvim/onedarker.nvim"
+ },
+ ["packer.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/packer.nvim",
+ url = "https://github.com/wbthomason/packer.nvim"
+ },
+ playground = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/playground",
+ url = "https://github.com/nvim-treesitter/playground"
+ },
+ ["plenary.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/plenary.nvim",
+ url = "https://github.com/nvim-lua/plenary.nvim"
+ },
+ ["popup.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/popup.nvim",
+ url = "https://github.com/nvim-lua/popup.nvim"
+ },
+ ["project.nvim"] = {
+ config = { "\27LJ\2\n?\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\22lvim.core.project\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/project.nvim",
+ url = "https://github.com/ahmedkhalf/project.nvim"
+ },
+ ["schemastore.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/schemastore.nvim",
+ url = "https://github.com/b0o/schemastore.nvim"
+ },
+ ["structlog.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/structlog.nvim",
+ url = "https://github.com/Tastyep/structlog.nvim"
+ },
+ ["symbols-outline.nvim"] = {
+ config = { "\27LJ\2\n]\0\0\3\0\4\0\a6\0\0\0'\2\1\0B\0\2\0029\0\2\0005\2\3\0B\0\2\1K\0\1\0\1\0\2\nwidth\3\18\19autofold_depth\3\1\nsetup\20symbols-outline\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/symbols-outline.nvim",
+ url = "https://github.com/simrat39/symbols-outline.nvim"
+ },
+ ["telescope-fzf-native.nvim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/telescope-fzf-native.nvim",
+ url = "https://github.com/nvim-telescope/telescope-fzf-native.nvim"
+ },
+ ["telescope.nvim"] = {
+ config = { "\27LJ\2\nA\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\24lvim.core.telescope\frequire\0" },
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/telescope.nvim",
+ url = "https://github.com/nvim-telescope/telescope.nvim"
+ },
+ ["toggleterm.nvim"] = {
+ config = { "\27LJ\2\n@\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\23lvim.core.terminal\frequire\0" },
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/toggleterm.nvim",
+ url = "https://github.com/akinsho/toggleterm.nvim"
+ },
+ ["vim-floaterm"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/vim-floaterm",
+ url = "https://github.com/voldikss/vim-floaterm"
+ },
+ ["vim-wakatime"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/vim-wakatime",
+ url = "https://github.com/wakatime/vim-wakatime"
+ },
+ ["vim-wayland-clipboard"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/vim-wayland-clipboard",
+ url = "https://github.com/jasonccox/vim-wayland-clipboard"
+ },
+ ["which-key.nvim"] = {
+ config = { "\27LJ\2\nA\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\24lvim.core.which-key\frequire\0" },
+ loaded = false,
+ needs_bufread = false,
+ only_cond = false,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/opt/which-key.nvim",
+ url = "https://github.com/folke/which-key.nvim"
+ },
+ ["yuck.vim"] = {
+ loaded = true,
+ path = "/home/itsdrike/.local/share/lunarvim/site/pack/packer/start/yuck.vim",
+ url = "https://github.com/elkowar/yuck.vim"
+ }
+}
+
+time([[Defining packer_plugins]], false)
+local module_lazy_loads = {
+ ["^lua%-dev"] = "lua-dev.nvim"
+}
+local lazy_load_called = {['packer.load'] = true}
+local function lazy_load_module(module_name)
+ local to_load = {}
+ if lazy_load_called[module_name] then return nil end
+ lazy_load_called[module_name] = true
+ for module_pat, plugin_name in pairs(module_lazy_loads) do
+ if not _G.packer_plugins[plugin_name].loaded and string.match(module_name, module_pat) then
+ to_load[#to_load + 1] = plugin_name
+ end
+ end
+
+ if #to_load > 0 then
+ require('packer.load')(to_load, {module = module_name}, _G.packer_plugins)
+ local loaded_mod = package.loaded[module_name]
+ if loaded_mod then
+ return function(modname) return loaded_mod end
+ end
+ end
+end
+
+if not vim.g.packer_custom_loader_enabled then
+ table.insert(package.loaders, 1, lazy_load_module)
+ vim.g.packer_custom_loader_enabled = true
+end
+
+-- Config for: telescope.nvim
+time([[Config for telescope.nvim]], true)
+try_loadstring("\27LJ\2\nA\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\24lvim.core.telescope\frequire\0", "config", "telescope.nvim")
+time([[Config for telescope.nvim]], false)
+-- Config for: nvim-cmp
+time([[Config for nvim-cmp]], true)
+try_loadstring("\27LJ\2\n`\0\0\3\0\6\0\v6\0\0\0009\0\1\0009\0\2\0\15\0\0\0X\1\56\0\3\0'\2\4\0B\0\2\0029\0\5\0B\0\1\1K\0\1\0\nsetup\18lvim.core.cmp\frequire\bcmp\fbuiltin\tlvim\0", "config", "nvim-cmp")
+time([[Config for nvim-cmp]], false)
+-- Config for: minimap.vim
+time([[Config for minimap.vim]], true)
+try_loadstring("\27LJ\2\n<\0\0\3\0\3\0\0056\0\0\0009\0\1\0'\2\2\0B\0\2\1K\0\1\0\29let g:minimap_width = 10\bcmd\bvim\0", "config", "minimap.vim")
+time([[Config for minimap.vim]], false)
+-- Config for: onedarker.nvim
+time([[Config for onedarker.nvim]], true)
+try_loadstring("\27LJ\2\n\1\0\0\3\0\t\0\0196\0\0\0\15\0\0\0X\1\156\0\0\0009\0\1\0\a\0\2\0X\0\v6\0\3\0'\2\2\0B\0\2\0029\0\4\0B\0\1\0016\0\0\0009\0\5\0009\0\6\0009\0\a\0'\1\2\0=\1\b\0K\0\1\0\ntheme\foptions\flualine\fbuiltin\nsetup\frequire\14onedarker\16colorscheme\tlvim\30\1\0\3\0\2\0\0046\0\0\0003\2\1\0B\0\2\1K\0\1\0\0\npcall\0", "config", "onedarker.nvim")
+time([[Config for onedarker.nvim]], false)
+-- Config for: nvim-dap
+time([[Config for nvim-dap]], true)
+try_loadstring("\27LJ\2\n;\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\18lvim.core.dap\frequire\0", "config", "nvim-dap")
+time([[Config for nvim-dap]], false)
+-- Config for: nvim-treesitter
+time([[Config for nvim-treesitter]], true)
+try_loadstring("\27LJ\2\nB\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\25lvim.core.treesitter\frequire\0", "config", "nvim-treesitter")
+time([[Config for nvim-treesitter]], false)
+-- Config for: nvim-treesitter-context
+time([[Config for nvim-treesitter-context]], true)
+try_loadstring("\27LJ\2\n\1\0\0\5\0\b\0\v6\0\0\0'\2\1\0B\0\2\0029\0\2\0005\2\3\0005\3\5\0005\4\4\0=\4\6\3=\3\a\2B\0\2\1K\0\1\0\rpatterns\fdefault\1\0\0\1\t\0\0\nclass\rfunction\vmethod\nwhile\bfor\aif\vswitch\tcase\1\0\3\rthrottle\2\venable\2\14max_lines\3\0\nsetup\23treesitter-context\frequire\0", "config", "nvim-treesitter-context")
+time([[Config for nvim-treesitter-context]], false)
+-- Config for: lf.vim
+time([[Config for lf.vim]], true)
+try_loadstring("\27LJ\2\n-\0\0\2\0\3\0\0056\0\0\0009\0\1\0)\1\0\0=\1\2\0K\0\1\0\16lf_map_keys\6g\bvim\0", "config", "lf.vim")
+time([[Config for lf.vim]], false)
+-- Config for: alpha-nvim
+time([[Config for alpha-nvim]], true)
+try_loadstring("\27LJ\2\n=\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\20lvim.core.alpha\frequire\0", "config", "alpha-nvim")
+time([[Config for alpha-nvim]], false)
+-- Config for: nvim-notify
+time([[Config for nvim-notify]], true)
+try_loadstring("\27LJ\2\n>\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\21lvim.core.notify\frequire\0", "config", "nvim-notify")
+time([[Config for nvim-notify]], false)
+-- Config for: lualine.nvim
+time([[Config for lualine.nvim]], true)
+try_loadstring("\27LJ\2\n?\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\22lvim.core.lualine\frequire\0", "config", "lualine.nvim")
+time([[Config for lualine.nvim]], false)
+-- Config for: project.nvim
+time([[Config for project.nvim]], true)
+try_loadstring("\27LJ\2\n?\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\22lvim.core.project\frequire\0", "config", "project.nvim")
+time([[Config for project.nvim]], false)
+-- Config for: nvim-tree.lua
+time([[Config for nvim-tree.lua]], true)
+try_loadstring("\27LJ\2\n@\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\23lvim.core.nvimtree\frequire\0", "config", "nvim-tree.lua")
+time([[Config for nvim-tree.lua]], false)
+-- Config for: LuaSnip
+time([[Config for LuaSnip]], true)
+try_loadstring("\27LJ\2\n\3\0\0\v\0\23\00166\0\0\0'\2\1\0B\0\2\0024\1\0\0006\2\2\0009\2\3\0029\2\4\0029\2\5\0029\2\6\2\15\0\2\0X\3\f\21\2\1\0\22\2\0\0029\3\a\0006\5\b\0B\5\1\2'\6\t\0'\a\n\0'\b\v\0'\t\f\0'\n\r\0B\3\a\2<\3\2\0019\2\a\0006\4\14\0B\4\1\2'\5\15\0B\2\3\0029\3\16\0\18\5\2\0B\3\2\2\15\0\3\0X\4\3\21\3\1\0\22\3\0\3<\2\3\0016\3\0\0'\5\17\0B\3\2\0029\3\18\3B\3\1\0016\3\0\0'\5\19\0B\3\2\0029\3\18\0035\5\20\0=\1\21\5B\3\2\0016\3\0\0'\5\22\0B\3\2\0029\3\18\3B\3\1\1K\0\1\0\"luasnip.loaders.from_snipmate\npaths\1\0\0 luasnip.loaders.from_vscode\14lazy_load\29luasnip.loaders.from_lua\17is_directory\rsnippets\19get_config_dir\22friendly-snippets\nstart\vpacker\tpack\tsite\20get_runtime_dir\15join_paths\22friendly_snippets\fsources\fluasnip\fbuiltin\tlvim\15lvim.utils\frequire\2\0", "config", "LuaSnip")
+time([[Config for LuaSnip]], false)
+-- Config for: mason.nvim
+time([[Config for mason.nvim]], true)
+try_loadstring("\27LJ\2\n=\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\20lvim.core.mason\frequire\0", "config", "mason.nvim")
+time([[Config for mason.nvim]], false)
+-- Config for: nvim-autopairs
+time([[Config for nvim-autopairs]], true)
+try_loadstring("\27LJ\2\nA\0\0\3\0\3\0\0066\0\0\0'\2\1\0B\0\2\0029\0\2\0B\0\1\1K\0\1\0\nsetup\24lvim.core.autopairs\frequire\0", "config", "nvim-autopairs")
+time([[Config for nvim-autopairs]], false)
+-- Config for: symbols-outline.nvim
+time([[Config for symbols-outline.nvim]], true)
+try_loadstring("\27LJ\2\n]\0\0\3\0\4\0\a6\0\0\0'\2\1\0B\0\2\0029\0\2\0005\2\3\0B\0\2\1K\0\1\0\1\0\2\nwidth\3\18\19autofold_depth\3\1\nsetup\20symbols-outline\frequire\0", "config", "symbols-outline.nvim")
+time([[Config for symbols-outline.nvim]], false)
+vim.cmd [[augroup packer_load_aucmds]]
+vim.cmd [[au!]]
+ -- Event lazy-loads
+time([[Defining lazy-load event autocommands]], true)
+vim.cmd [[au VimEnter * ++once lua require("packer.load")({'copilot.lua'}, { event = "VimEnter *" }, _G.packer_plugins)]]
+vim.cmd [[au BufWinEnter * ++once lua require("packer.load")({'which-key.nvim', 'bufferline.nvim', 'toggleterm.nvim'}, { event = "BufWinEnter *" }, _G.packer_plugins)]]
+vim.cmd [[au BufReadPost * ++once lua require("packer.load")({'nvim-ts-context-commentstring'}, { event = "BufReadPost *" }, _G.packer_plugins)]]
+vim.cmd [[au BufRead * ++once lua require("packer.load")({'gitsigns.nvim', 'lsp_signature.nvim', 'Comment.nvim'}, { event = "BufRead *" }, _G.packer_plugins)]]
+time([[Defining lazy-load event autocommands]], false)
+vim.cmd("augroup END")
+
+_G._packer.inside_compile = false
+if _G._packer.needs_bufread == true then
+ vim.cmd("doautocmd BufRead")
+end
+_G._packer.needs_bufread = false
+
+if should_profile then save_profiles() end
+
+end)
+
+if not no_errors then
+ error_msg = error_msg:gsub('"', '\\"')
+ vim.api.nvim_command('echohl ErrorMsg | echom "Error in packer_compiled: '..error_msg..'" | echom "Please check your config for correctness" | echohl None')
+end
diff --git a/home/.config/lvim/snippets/package.json b/home/.config/lvim/snippets/package.json
new file mode 100644
index 0000000..5ff827f
--- /dev/null
+++ b/home/.config/lvim/snippets/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "nvim-snippets",
+ "author": "ItsDrike",
+ "engines": {
+ "vscode": "^1.11.0"
+ },
+ "contributes": {
+ "snippets": [
+ {
+ "language": "python",
+ "path": "./python.json"
+ }
+ ]
+ }
+}
diff --git a/home/.config/lvim/snippets/python.json b/home/.config/lvim/snippets/python.json
new file mode 100644
index 0000000..680c8a1
--- /dev/null
+++ b/home/.config/lvim/snippets/python.json
@@ -0,0 +1,21 @@
+{
+ "future.__annotations__": {
+ "prefix": "futann",
+ "body": "from __future__ import annotations\n",
+ "description": "Add __future__.annoations import."
+ },
+ "script": {
+ "prefix": "script",
+ "body": [
+ "#!/usr/bin/env python3",
+ "",
+ "def main() -> None:",
+ "\t${1:...}",
+ "",
+ "",
+ "if __name__ == \"__main__\":",
+ "\tmain()"
+ ],
+ "description": "print Hello, World!"
+ }
+}
diff --git a/home/.config/lvim/spell/en.utf-8.add b/home/.config/lvim/spell/en.utf-8.add
new file mode 100644
index 0000000..e63c2e3
--- /dev/null
+++ b/home/.config/lvim/spell/en.utf-8.add
@@ -0,0 +1,24 @@
+Flake8
+Isort
+linter
+flake8
+isort
+TOML
+YAML
+linters
+MyPy
+Pyright
+pyright
+VSCode
+Pylance
+Docstrings
+Docstring
+docstrings
+docstring
+BSPWM
+Xmonad
+deserialized
+serializable
+ItsDrike
+itsdrike
+protonmail
diff --git a/home/.config/lvim/spell/en.utf-8.add.spl b/home/.config/lvim/spell/en.utf-8.add.spl
new file mode 100644
index 0000000..107bdb0
Binary files /dev/null and b/home/.config/lvim/spell/en.utf-8.add.spl differ
diff --git a/home/.config/lvim/syntax/apparmor.vim b/home/.config/lvim/syntax/apparmor.vim
new file mode 100644
index 0000000..428ce96
--- /dev/null
+++ b/home/.config/lvim/syntax/apparmor.vim
@@ -0,0 +1,283 @@
+" generated from apparmor.vim.in by create-apparmor.vim.py
+" do not edit this file - edit apparmor.vim.in or create-apparmor.vim.py instead
+
+" ----------------------------------------------------------------------
+" Copyright (c) 2005 Novell, Inc. All Rights Reserved.
+" Copyright (c) 2006-2012 Christian Boltz. All Rights Reserved.
+"
+" This program is free software; you can redistribute it and/or
+" modify it under the terms of version 2 of the GNU General Public
+" License as published by the Free Software Foundation.
+"
+" 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, contact Novell, Inc.
+"
+" To contact Novell about this file by physical or electronic mail,
+" you may find current contact information at www.novell.com.
+"
+" To contact Christian Boltz about this file by physical or electronic
+" mail, you may find current contact information at www.cboltz.de/en/kontakt.
+"
+" If you want to report a bug via bugzilla.novell.com, please assign it
+" to suse-beta[AT]cboltz.de (replace [AT] with @).
+" ----------------------------------------------------------------------
+"
+" stick this file into ~/.vim/syntax/ and add these commands into your .vimrc
+" to have vim automagically use this syntax file for these directories:
+"
+" autocmd BufNewFile,BufRead /etc/apparmor.d/* set syntax=apparmor
+" autocmd BufNewFile,BufRead /usr/share/apparmor/extra-profiles/* set syntax=apparmor
+
+" profiles are case sensitive
+syntax case match
+
+" color setup...
+
+" adjust colors according to the background
+
+" switching colors depending on the background color doesn't work
+" unfortunately, so we use colors that work with light and dark background.
+" Patches welcome ;-)
+
+"if &background == "light"
+" light background
+ hi sdProfileName ctermfg=lightblue
+ hi sdHatName ctermfg=darkblue
+ hi sdExtHat ctermfg=darkblue
+" hi sdComment2 ctermfg=darkblue
+ hi sdGlob ctermfg=darkmagenta
+ hi sdAlias ctermfg=darkmagenta
+ hi sdEntryWriteExec ctermfg=black ctermbg=yellow
+ hi sdEntryUX ctermfg=darkred cterm=underline
+ hi sdEntryUXe ctermfg=darkred
+ hi sdEntryIX ctermfg=darkcyan
+ hi sdEntryM ctermfg=darkcyan
+ hi sdEntryPX ctermfg=darkgreen cterm=underline
+ hi sdEntryPXe ctermfg=darkgreen
+ hi sdEntryW ctermfg=darkyellow
+ hi sdCap ctermfg=lightblue
+ hi sdSetCap ctermfg=black ctermbg=yellow
+ hi sdNetwork ctermfg=lightblue
+ hi sdNetworkDanger ctermfg=darkred
+ hi sdCapKey cterm=underline ctermfg=lightblue
+ hi sdCapDanger ctermfg=darkred
+ hi sdRLimit ctermfg=lightblue
+ hi def link sdEntryR Normal
+ hi def link sdEntryK Normal
+ hi def link sdFlags Normal
+ hi sdEntryChangeProfile ctermfg=darkgreen cterm=underline
+"else
+" dark background
+" hi sdProfileName ctermfg=white
+" hi sdHatName ctermfg=white
+" hi sdGlob ctermfg=magenta
+" hi sdEntryWriteExec ctermfg=black ctermbg=yellow
+" hi sdEntryUX ctermfg=red cterm=underline
+" hi sdEntryUXe ctermfg=red
+" hi sdEntryIX ctermfg=cyan
+" hi sdEntryM ctermfg=cyan
+" hi sdEntryPX ctermfg=green cterm=underline
+" hi sdEntryPXe ctermfg=green
+" hi sdEntryW ctermfg=yellow
+" hi sdCap ctermfg=lightblue
+" hi sdCapKey cterm=underline ctermfg=lightblue
+" hi def link sdEntryR Normal
+" hi def link sdFlags Normal
+" hi sdCapDanger ctermfg=red
+"endif
+
+hi def link sdInclude Include
+high def link sdComment Comment
+"high def link sdComment2 Comment
+high def link sdFlagKey TODO
+high def link sdError ErrorMsg
+
+
+" always sync from the start. should be relatively quick since we don't have
+" that many rules and profiles shouldn't be _extremely_ large...
+syn sync fromstart
+
+syn keyword sdFlagKey complain debug
+
+" highlight invalid syntax
+syn match sdError /{/ contained
+syn match sdError /}/
+syn match sdError /^.*$/ contains=sdComment "highlight all non-valid lines as error
+" TODO: do not mark lines containing only whitespace as error
+
+" TODO: the sdGlob pattern is not anchored with ^ and $, so it matches all lines matching ^@{...}.*
+" This allows incorrect lines also and should be checked better.
+" This also (accidently ;-) includes variable definitions (@{FOO}=/bar)
+" TODO: make a separate pattern for variable definitions, then mark sdGlob as contained
+syn match sdGlob /\v\?|\*|\{.*,.*\}|[[^\]]\+\]|\@\{[a-zA-Z][a-zA-Z0-9_]*\}/
+
+syn match sdAlias /\v^alias\s+(\/|\@\{\S*\})\S*\s+-\>\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob
+
+" syn match sdComment /#.*/
+
+syn cluster sdEntry contains=sdEntryWriteExec,sdEntryR,sdEntryW,sdEntryIX,sdEntryPX,sdEntryPXe,sdEntryUX,sdEntryUXe,sdEntryM,sdCap,sdSetCap,sdExtHat,sdRLimit,sdNetwork,sdNetworkDanger,sdEntryChangeProfile
+
+
+" TODO: support audit and deny keywords for all rules (not only for files)
+" TODO: higlight audit and deny keywords everywhere
+
+" Capability line
+
+" normal capabilities - really keep this list? syn match sdCap should be enough... (difference: sdCapKey words would loose underlining)
+syn keyword sdCapKey audit_read block_suspend chown dac_override dac_read_search fowner fsetid ipc_lock ipc_owner kill lease linux_immutable mknod net_admin net_bind_service net_broadcast net_raw setfcap setgid setpcap setuid syslog sys_boot sys_chroot sys_nice sys_pacct sys_ptrace sys_resource sys_time sys_tty_config wake_alarm
+
+" dangerous capabilities - highlighted separately
+syn keyword sdCapDanger audit_control audit_write mac_override mac_admin set_fcap sys_admin sys_module sys_rawio
+
+" full line. Keywords are from sdCapKey + sdCapDanger
+syn match sdCap /\v^\s*(audit\s+)?(deny\s+|allow\s+)?capability\s+((audit_control|audit_read|audit_write|block_suspend|chown|dac_override|dac_read_search|fowner|fsetid|ipc_lock|ipc_owner|kill|lease|linux_immutable|mac_admin|mac_override|mknod|net_admin|net_bind_service|net_broadcast|net_raw|setfcap|setgid|setpcap|setuid|syslog|sys_admin|sys_boot|sys_chroot|sys_module|sys_nice|sys_pacct|sys_ptrace|sys_rawio|sys_resource|sys_time|sys_tty_config|wake_alarm)\s+)*(audit_control|audit_read|audit_write|block_suspend|chown|dac_override|dac_read_search|fowner|fsetid|ipc_lock|ipc_owner|kill|lease|linux_immutable|mac_admin|mac_override|mknod|net_admin|net_bind_service|net_broadcast|net_raw|setfcap|setgid|setpcap|setuid|syslog|sys_admin|sys_boot|sys_chroot|sys_module|sys_nice|sys_pacct|sys_ptrace|sys_rawio|sys_resource|sys_time|sys_tty_config|wake_alarm)\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdCapKey,sdCapDanger,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+" all capabilities ('capability' without any keyword)
+syn match sdCapDanger /\v^\s*(audit\s+)?(deny\s+|allow\s+)?capability\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" Network line
+" Syntax: network domain (inet, ...) type (stream, ...) protocol (tcp, ...)
+" TODO: 'owner' isn't supported, but will be (JJ, 2011-01-11)
+syn match sdNetwork /\v^\s*(audit\s+)?(deny\s+|allow\s+)?network(\s+(unix|inet|ax25|ipx|appletalk|netrom|bridge|atmpvc|x25|inet6|rose|netbeui|security|key|netlink|packet|ash|econet|atmsvc|rds|sna|irda|pppox|wanpipe|llc|can|tipc|bluetooth|iucv|rxrpc|isdn|phonet|ieee802154|caif|alg|nfc|vsock))?(\s+(stream|dgram|seqpacket|rdm|packet))?(\s+tcp|\s+udp|\s+icmp)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+" network rules containing 'raw'
+syn match sdNetworkDanger /\v^\s*(audit\s+)?(deny\s+|allow\s+)?network(\s+(unix|inet|ax25|ipx|appletalk|netrom|bridge|atmpvc|x25|inet6|rose|netbeui|security|key|netlink|packet|ash|econet|atmsvc|rds|sna|irda|pppox|wanpipe|llc|can|tipc|bluetooth|iucv|rxrpc|isdn|phonet|ieee802154|caif|alg|nfc|vsock))?(\s+(raw))(\s+tcp|\s+udp|\s+icmp)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+" 'all networking' includes raw -> mark as dangerous
+syn match sdNetworkDanger /\v^\s*(audit\s+)?(deny\s+|allow\s+)?network\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+
+" Change Profile
+" TODO: audit and deny support will be added (JJ, 2011-01-11)
+syn match sdEntryChangeProfile /\v^\s*change_profile\s+-\>\s+\S+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+
+" rlimit
+" TODO: audit and deny support will be added (JJ, 2011-01-11)
+"
+"syn match sdRLimit /\v^\s*rlimit\s+()\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment
+syn match sdRLimit /\v^\s*set\s+rlimit\s+(nofile|ofile|nproc|rtprio)\s+\<\=\s+[0-9]+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment
+syn match sdRLimit /\v^\s*set\s+rlimit\s+(locks|sigpending)\s+\<\=\s+[0-9]+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment
+syn match sdRLimit /\v^\s*set\s+rlimit\s+(fsize|data|stack|core|rss|as|memlock|msgqueue)\s+\<\=\s+[0-9]+([KMG]B)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment
+syn match sdRLimit /\v^\s*set\s+rlimit\s+nice\s+\<\=\s+(-1?[0-9]|-20|1?[0-9])\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment
+syn match sdRLimit /\v^\s*set\s+rlimit\s+cpu\s+\<\=\s+[0-9]+(seconds|minutes|hours|days)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment
+syn match sdRLimit /\v^\s*set\s+rlimit\s+rttime\s+\<\=\s+[0-9]+(ms|seconds|minutes)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment
+syn match sdRLimit /\v^\s*set\s+rlimit\s+(cpu|rttime|nofile|nproc|rtprio|locks|sigpending|fsize|data|stack|core|rss|as|memlock|msgqueue|nice)\s+\<\=\s+infinity\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment
+
+" link rules
+syn match sdEntryW /\v^\s+(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?link\s+(subset\s+)?(\/|\@\{\S*\})\S*\s+-\>\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob
+
+
+syn match sdExtHat /\v^\s+(\^|profile\s+)\S+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdComment " hat without {...}
+
+
+
+
+syn match sdProfileName /\v^((profile\s+)?\/\S+|profile\s+([a-zA-Z0-9]\S*\s)?\S+)\s+((flags\s*\=\s*)?\(\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted)(\s*,\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted))*\s*\)\s+)=\{/ contains=sdProfileStart,sdHatName,sdFlags,sdComment,sdGlob
+syn match sdProfileStart /{/ contained
+syn match sdProfileEnd /^}\s*(#.*)?$/ contained " TODO: syn region does not (yet?) allow usage of comment in end=
+ " TODO: Removing the $ mark from end= will allow non-comments also :-(
+syn match sdHatName /\v^\s+(\^|profile\s+)\S+\s+((flags\s*\=\s*)?\(\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted)(\s*,\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted))*\s*\)\s+)=\{/ contains=sdProfileStart,sdFlags,sdComment
+syn match sdHatStart /{/ contained
+syn match sdHatEnd /}/ contained " TODO: allow comments + [same as for syn match sdProfileEnd]
+syn match sdFlags /\v((flags\s*\=\s*)?\(\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted)(\s*,\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted))*\s*\)\s+)/ contained contains=sdFlagKey
+
+syn match sdComment /\s*#.*$/
+" NOTE: contains=sdComment changes #include highlighting to comment color.
+" NOTE: Comment highlighting still works without contains=sdComment.
+syn match sdInclude /\s*#include\s<\S*>/ " TODO: doesn't check until $
+syn match sdInclude /\s*include\s<\S*>/ " TODO: doesn't check until $
+
+" basic profile block...
+" \s+ does not work in end=, therefore using \s\s*
+syn region Normal start=/\v^(profile\s+)?\S+\s+((flags\s*\=\s*)?\(\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted)(\s*,\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted))*\s*\)\s+)=\{/ matchgroup=sdProfileEnd end=/^}\s*$/ contains=sdProfileName,Hat,@sdEntry,sdComment,sdError,sdInclude
+syn region Hat start=/\v^\s+(\^|profile\s+)\S+\s+((flags\s*\=\s*)?\(\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted)(\s*,\s*(complain|audit|attach_disconnected|no_attach_disconnected|chroot_attach|chroot_no_attach|chroot_relative|namespace_relative|mediate_deleted|delegate_deleted))*\s*\)\s+)=\{/ matchgroup=sdHatEnd end=/^\s\s*}\s*$/ contains=sdHatName,@sdEntry,sdComment,sdError,sdInclude
+
+" file permissions
+
+
+
+
+
+" file rules added with create_file_rule()
+
+" write + exec/mmap - danger! (known bug: accepts aw to keep things simple)
+syn match sdEntryWriteExec /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(l|r|w|a|m|k|[iuUpPcC]x)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryWriteExec /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(l|r|w|a|m|k|[iuUpPcC]x)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryWriteExec /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(l|r|w|a|m|k|[iuUpPcC]x)+(\s+-\>\s+\S+)?\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryWriteExec /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(l|r|w|a|m|k|[iuUpPcC]x)+(\s+-\>\s+\S+)?\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" ux(mr) - unconstrained entry, flag the line red. also includes pux which is unconstrained if no profile exists
+syn match sdEntryUX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(r|m|k|ux|pux)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryUX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(r|m|k|ux|pux)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryUX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|ux|pux)+(\s+-\>\s+\S+)?\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryUX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|ux|pux)+(\s+-\>\s+\S+)?\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" Ux(mr) and PUx(mr) - like ux + clean environment
+syn match sdEntryUXe /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(r|m|k|Ux|PUx)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryUXe /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(r|m|k|Ux|PUx)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryUXe /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|Ux|PUx)+(\s+-\>\s+\S+)?\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryUXe /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|Ux|PUx)+(\s+-\>\s+\S+)?\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" px/cx/pix/cix(mrk) - standard exec entry, flag the line blue
+syn match sdEntryPX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(r|m|k|px|cx|pix|cix)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryPX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(r|m|k|px|cx|pix|cix)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryPX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|px|cx|pix|cix)+(\s+-\>\s+\S+)?\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryPX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|px|cx|pix|cix)+(\s+-\>\s+\S+)?\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" Px/Cx/Pix/Cix(mrk) - like px/cx + clean environment
+syn match sdEntryPXe /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(r|m|k|Px|Cx|Pix|Cix)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryPXe /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(r|m|k|Px|Cx|Pix|Cix)+(\s+-\>\s+\S+)?\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryPXe /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|Px|Cx|Pix|Cix)+(\s+-\>\s+\S+)?\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryPXe /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|Px|Cx|Pix|Cix)+(\s+-\>\s+\S+)?\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" ix(mr) - standard exec entry, flag the line green
+syn match sdEntryIX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(r|m|k|ix)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryIX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(r|m|k|ix)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryIX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|ix)+\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryIX /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k|ix)+\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" mr - mmap with PROT_EXEC
+syn match sdEntryM /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(r|m|k)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryM /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(r|m|k)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryM /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k)+\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryM /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(r|m|k)+\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" special case: deny x is allowed (does not need to be ix, px, ux or cx)
+syn match sdEntryM /\v^\s*(audit\s+)?deny\s+(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(r|m|k|x)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryM /\v^\s*(audit\s+)?deny\s+(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(r|m|k|x)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryM /\v^\s*(audit\s+)?deny\s+(owner\s+|other\s+)?(r|m|k|x)+\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryM /\v^\s*(audit\s+)?deny\s+(owner\s+|other\s+)?(r|m|k|x)+\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" write + append is an error
+syn match sdError /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+\S*(w\S*a|a\S*w)\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdError /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+\S*(w\S*a|a\S*w)\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdError /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?\S*(w\S*a|a\S*w)\S*\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdError /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?\S*(w\S*a|a\S*w)\S*\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" write entry, flag the line yellow
+syn match sdEntryW /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(l|r|w|k)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryW /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(l|r|w|k)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryW /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(l|r|w|k)+\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryW /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(l|r|w|k)+\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" append entry, flag the line yellow
+syn match sdEntryW /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+(l|r|a|k)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryW /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+(l|r|a|k)+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryW /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(l|r|a|k)+\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryW /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(l|r|a|k)+\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" read entry + locking, currently no highlighting
+syn match sdEntryK /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+[rlk]+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryK /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+[rlk]+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryK /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?[rlk]+\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryK /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?[rlk]+\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
+" read entry, no highlighting
+syn match sdEntryR /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?(\/|\@\{\S*\})\S*\s+[rl]+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryR /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?"(\/|\@\{\S*\})\S*"\s+[rl]+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryR /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?[rl]+\s+(\/|\@\{\S*\})\S*\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+syn match sdEntryR /\v^\s*(audit\s+)?(deny\s+|allow\s+)?(owner\s+|other\s+)?[rl]+\s+"(\/|\@\{\S*\})\S*"+\s*,(\s*$|(\s*#.*$)\@=)/ contains=sdGlob,sdComment nextgroup=@sdEntry,sdComment,sdError,sdInclude
+
diff --git a/home/.config/lvim/syntax/apparmor.vim.bak b/home/.config/lvim/syntax/apparmor.vim.bak
new file mode 120000
index 0000000..6dd60b5
--- /dev/null
+++ b/home/.config/lvim/syntax/apparmor.vim.bak
@@ -0,0 +1 @@
+/usr/share/vim/vimfiles/syntax/apparmor.vim
\ No newline at end of file
diff --git a/home/.config/mimeapps.list b/home/.config/mimeapps.list
new file mode 100644
index 0000000..736dc63
--- /dev/null
+++ b/home/.config/mimeapps.list
@@ -0,0 +1,14 @@
+
+[Default Applications]
+inode/directory=pcmanfm.desktop
+image/jpeg=org.nomacs.ImageLounge.desktop
+image/png=org.nomacs.ImageLounge.desktop
+image/gif=org.nomacs.ImageLounge.desktop
+application/pdf=firefox.desktop
+text/html=firefox.desktop
+x-scheme-handler/http=firefox.desktop
+x-scheme-handler/https=firefox.desktop
+x-scheme-handler/about=firefox.desktop
+x-scheme-handler-unknown=firefox.desktop
+application/json=nvim.desktop
+video/mp4=mpv.desktop
diff --git a/home/.config/mozilla/.keep b/home/.config/mozilla/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/home/.config/mpv/input.conf b/home/.config/mpv/input.conf
new file mode 100644
index 0000000..5ba5b69
--- /dev/null
+++ b/home/.config/mpv/input.conf
@@ -0,0 +1,25 @@
+# Vim keys seeking
+l seek 5
+h seek -5
+j seek -60
+k seek 60
+
+# Set A-B Loop key to g, since l was rebound
+g ab-loop
+
+# Swap i and I, use lowercase for toggle
+i script-binding stats/display-stats-toggle
+I script-binding stats/display-stats
+
+# Zooming
+- add video-zoom -.25
++ add video-zoom .25
+# Moving/panning video
+kp8 add video-pan-y .05
+kp6 add video-pan-x -.05
+kp2 add video-pan-y -.05
+kp4 add video-pan-x .05
+kp5 set video-pan-x 0; set video-pan-y 0; set video-zoom 0
+
+# Rotation
+ctrl+r cycle_values video-rotate "90" "180" "270" "0"
diff --git a/home/.config/mpv/input.conf.default b/home/.config/mpv/input.conf.default
new file mode 100644
index 0000000..38adf14
--- /dev/null
+++ b/home/.config/mpv/input.conf.default
@@ -0,0 +1,180 @@
+# mpv keybindings
+#
+# Location of user-defined bindings: ~/.config/mpv/input.conf
+#
+# Lines starting with # are comments. Use SHARP to assign the # key.
+# Copy this file and uncomment and edit the bindings you want to change.
+#
+# List of commands and further details: DOCS/man/input.rst
+# List of special keys: --input-keylist
+# Keybindings testing mode: mpv --input-test --force-window --idle
+#
+# Use 'ignore' to unbind a key fully (e.g. 'ctrl+a ignore').
+#
+# Strings need to be quoted and escaped:
+# KEY show-text "This is a single backslash: \\ and a quote: \" !"
+#
+# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with
+# the modifiers Shift, Ctrl, Alt and Meta (may not work on the terminal).
+#
+# The default keybindings are hardcoded into the mpv binary.
+# You can disable them completely with: --no-input-default-bindings
+
+# Developer note:
+# On compilation, this file is baked into the mpv binary, and all lines are
+# uncommented (unless '#' is followed by a space) - thus this file defines the
+# default key bindings.
+
+# If this is enabled, treat all the following bindings as default.
+#default-bindings start
+
+#MBTN_LEFT ignore # don't do anything
+#MBTN_LEFT_DBL cycle fullscreen # toggle fullscreen
+#MBTN_RIGHT cycle pause # toggle pause/playback mode
+#MBTN_BACK playlist-prev # skip to the previous file
+#MBTN_FORWARD playlist-next # skip to the next file
+
+# Mouse wheels, touchpad or other input devices that have axes
+# if the input devices supports precise scrolling it will also scale the
+# numeric value accordingly
+#WHEEL_UP seek 10 # seek 10 seconds forward
+#WHEEL_DOWN seek -10 # seek 10 seconds backward
+#WHEEL_LEFT add volume -2 # lower the volume
+#WHEEL_RIGHT add volume 2 # raise the volume
+
+## Seek units are in seconds, but note that these are limited by keyframes
+#RIGHT seek 5 # seek 5 seconds forward
+#LEFT seek -5 # seek 5 seconds backward
+#UP seek 60 # seek 1 minute forward
+#DOWN seek -60 # seek 1 minute backward
+# Do smaller, always exact (non-keyframe-limited), seeks with shift.
+# Don't show them on the OSD (no-osd).
+#Shift+RIGHT no-osd seek 1 exact # seek exactly 1 second forward
+#Shift+LEFT no-osd seek -1 exact # seek exactly 1 second backward
+#Shift+UP no-osd seek 5 exact # seek exactly 5 seconds forward
+#Shift+DOWN no-osd seek -5 exact # seek exactly 5 seconds backward
+#Ctrl+LEFT no-osd sub-seek -1 # seek to the previous subtitle
+#Ctrl+RIGHT no-osd sub-seek 1 # seek to the next subtitle
+#Ctrl+Shift+LEFT sub-step -1 # change subtitle timing such that the previous subtitle is displayed
+#Ctrl+Shift+RIGHT sub-step 1 # change subtitle timing such that the next subtitle is displayed
+#Alt+left add video-pan-x 0.1 # move the video right
+#Alt+right add video-pan-x -0.1 # move the video left
+#Alt+up add video-pan-y 0.1 # move the video down
+#Alt+down add video-pan-y -0.1 # move the video up
+#Alt++ add video-zoom 0.1 # zoom in
+#Alt+- add video-zoom -0.1 # zoom out
+#Alt+BS set video-zoom 0 ; set video-pan-x 0 ; set video-pan-y 0 # reset zoom and pan settings
+#PGUP add chapter 1 # seek to the next chapter
+#PGDWN add chapter -1 # seek to the previous chapter
+#Shift+PGUP seek 600 # seek 10 minutes forward
+#Shift+PGDWN seek -600 # seek 10 minutes backward
+#[ multiply speed 1/1.1 # decrease the playback speed
+#] multiply speed 1.1 # increase the playback speed
+#{ multiply speed 0.5 # halve the playback speed
+#} multiply speed 2.0 # double the playback speed
+#BS set speed 1.0 # reset the speed to normal
+#Shift+BS revert-seek # undo the previous (or marked) seek
+#Shift+Ctrl+BS revert-seek mark # mark the position for revert-seek
+#q quit # exit
+#Q quit-watch-later # exit and remember the playback position
+#q {encode} quit 4 # exit
+#ESC set fullscreen no # leave fullscreen
+#ESC {encode} quit 4 # exit
+#p cycle pause # toggle pause/playback mode
+#. frame-step # advance one frame and pause
+#, frame-back-step # go back by one frame and pause
+#SPACE cycle pause # toggle pause/playback mode
+#> playlist-next # skip to the next file
+#ENTER playlist-next # skip to the next file
+#< playlist-prev # skip to the previous file
+#O no-osd cycle-values osd-level 3 1 # toggle displaying the OSD on user interaction or always
+#o show-progress # show playback progress
+#P show-progress # show playback progress
+#i script-binding stats/display-stats # display information and statistics
+#I script-binding stats/display-stats-toggle # toggle displaying information and statistics
+#` script-binding console/enable # open the console
+#z add sub-delay -0.1 # shift subtitles 100 ms earlier
+#Z add sub-delay +0.1 # delay subtitles by 100 ms
+#x add sub-delay +0.1 # delay subtitles by 100 ms
+#ctrl++ add audio-delay 0.100 # change audio/video sync by delaying the audio
+#ctrl+- add audio-delay -0.100 # change audio/video sync by shifting the audio earlier
+#Shift+g add sub-scale +0.1 # increase the subtitle font size
+#Shift+f add sub-scale -0.1 # decrease the subtitle font size
+#9 add volume -2 # lower the volume
+#/ add volume -2 # lower the volume
+#0 add volume 2 # raise the volume
+#* add volume 2 # raise the volume
+#m cycle mute # toggle mute
+#1 add contrast -1 # decrease the contrast
+#2 add contrast 1 # increase the contrast
+#3 add brightness -1 # decrease the brightness
+#4 add brightness 1 # increase the brightness
+#5 add gamma -1 # decrease the gamma
+#6 add gamma 1 # increase the gamma
+#7 add saturation -1 # decrease the saturation
+#8 add saturation 1 # increase the saturation
+#Alt+0 set current-window-scale 0.5 # halve the window size
+#Alt+1 set current-window-scale 1.0 # reset the window size
+#Alt+2 set current-window-scale 2.0 # double the window size
+#d cycle deinterlace # toggle the deinterlacing filter
+#r add sub-pos -1 # move subtitles up
+#R add sub-pos +1 # move subtitles down
+#t add sub-pos +1 # move subtitles down
+#v cycle sub-visibility # hide or show the subtitles
+#Alt+v cycle secondary-sub-visibility # hide or show the secondary subtitles
+#V cycle sub-ass-vsfilter-aspect-compat # toggle stretching SSA/ASS subtitles with anamorphic videos to match the historical renderer
+#u cycle-values sub-ass-override "force" "no" # toggle overriding SSA/ASS subtitle styles with the normal styles
+#j cycle sub # switch subtitle track
+#J cycle sub down # switch subtitle track backwards
+#SHARP cycle audio # switch audio track
+#_ cycle video # switch video track
+#T cycle ontop # toggle placing the video on top of other windows
+#f cycle fullscreen # toggle fullscreen
+#s screenshot # take a screenshot of the video in its original resolution with subtitles
+#S screenshot video # take a screenshot of the video in its original resolution without subtitles
+#Ctrl+s screenshot window # take a screenshot of the window with OSD and subtitles
+#Alt+s screenshot each-frame # automatically screenshot every frame; issue this command again to stop taking screenshots
+#w add panscan -0.1 # decrease panscan
+#W add panscan +0.1 # shrink black bars by cropping the video
+#e add panscan +0.1 # shrink black bars by cropping the video
+#A cycle-values video-aspect-override "16:9" "4:3" "2.35:1" "-1" # cycle the video aspect ratio ("-1" is the container aspect)
+#POWER quit # exit
+#PLAY cycle pause # toggle pause/playback mode
+#PAUSE cycle pause # toggle pause/playback mode
+#PLAYPAUSE cycle pause # toggle pause/playback mode
+#PLAYONLY set pause no # unpause
+#PAUSEONLY set pause yes # pause
+#STOP quit # exit
+#FORWARD seek 60 # seek 1 minute forward
+#REWIND seek -60 # seek 1 minute backward
+#NEXT playlist-next # skip to the next file
+#PREV playlist-prev # skip to the previous file
+#VOLUME_UP add volume 2 # raise the volume
+#VOLUME_DOWN add volume -2 # lower the volume
+#MUTE cycle mute # toggle mute
+#CLOSE_WIN quit # exit
+#CLOSE_WIN {encode} quit 4 # exit
+#ctrl+w quit # exit
+#E cycle edition # switch edition
+#l ab-loop # set/clear A-B loop points
+#L cycle-values loop-file "inf" "no" # toggle infinite looping
+#ctrl+c quit 4 # exit
+#DEL script-binding osc/visibility # cycle OSC visibility between never, auto (mouse-move) and always
+#ctrl+h cycle-values hwdec "auto" "no" # toggle hardware decoding
+#F8 show-text ${playlist} # show the playlist
+#F9 show-text ${track-list} # show the list of video, audio and sub tracks
+
+#
+# Legacy bindings (may or may not be removed in the future)
+#
+#! add chapter -1 # seek to the previous chapter
+#@ add chapter 1 # seek to the next chapter
+
+#
+# Not assigned by default
+# (not an exhaustive list of unbound commands)
+#
+
+# ? cycle sub-forced-only # toggle DVD forced subs
+# ? stop # stop playback (quit or enter idle mode)
+
diff --git a/home/.config/mpv/mpv.conf b/home/.config/mpv/mpv.conf
new file mode 100644
index 0000000..3c30981
--- /dev/null
+++ b/home/.config/mpv/mpv.conf
@@ -0,0 +1 @@
+loop=yes
diff --git a/home/.config/nomacs/Image Lounge.conf b/home/.config/nomacs/Image Lounge.conf
new file mode 100644
index 0000000..2fcb47a
--- /dev/null
+++ b/home/.config/nomacs/Image Lounge.conf
@@ -0,0 +1,92 @@
+[General]
+DkEditDock=2
+DkExplorer=1
+firstTime=false
+geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x3\xc7\0\0\x2\x38\0\0\au\0\0\x4\x32\0\0\x3\xc7\0\0\x2\x38\0\0\au\0\0\x4-\0\0\0\0\x2\0\0\0\a\x80\0\0\x3\xc7\0\0\x2\x38\0\0\au\0\0\x4\x32)
+geometryNomacs=@Rect(967 568 943 507)
+windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x3\0\0\0\0\0\0\x1\0\0\0\x4\x4\xfc\x2\0\0\0\x1\xfb\0\0\0\x14\0\x44\0k\0\x45\0x\0p\0l\0o\0r\0\x65\0r\0\0\0\0\x34\0\0\x4\x4\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\xdd\0\0\x3\xc4\xfc\x2\0\0\0\x1\xfb\0\0\0\x14\0\x44\0k\0\x45\0\x64\0i\0t\0\x44\0o\0\x63\0k\0\0\0\0\x1e\0\0\x3\xc4\0\0\0\0\0\0\0\0\0\0\0\x3\0\0\a\x80\0\0\0>\xfc\x1\0\0\0\x1\xfb\0\0\0\x10\0\x63\0r\0o\0p\0\x44\0o\0\x63\0k\0\0\0\0\0\0\0\a\x80\0\0\0\0\0\0\0\0\0\0\x3\xaf\0\0\x1\xe4\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x1\0\0\0\x16\0\x45\0\x64\0i\0t\0T\0o\0o\0l\0\x42\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)
+
+[AppSettings]
+appMode=0
+currentAppMode=0
+defaultJpgQuality=97
+firstTime.nomacs.3=false
+hideAllPanels=true
+showPlayer=@Variant(\0\0\0\r\0\0\0\x6\0)
+
+[CustomPluginShortcuts]
+Composite%20Image=Composite Image
+Crop%20to%20Metadata=Crop to Metadata
+Crop%20to%20Page=Crop to Page
+Draw%20to%20Page=Draw to Page
+Fake%20Miniatures=Fake Miniatures
+Image%20Transform=Image Transform
+Paint%20on%20Image=Paint on Image
+
+[DisplaySettings]
+bgColorNoMacsRGBA=4281545523
+bgColorWidgetRGBA=2852126720
+fadeSec=@Variant(\0\0\0\x87\0\0\0\0)
+fontColorRGBA=4292730333
+highlightColorRGBA=4278233855
+iconColorRGBA=4292730333
+iconSize=18
+showCrop=true
+themeName312=Dark-Theme.css
+transition=0
+zoomToFit=true
+
+[DkAppManager]
+Apps\size=0
+
+[DkCompressionDialog]
+CompressionCombo0=0
+bgCompressionColor0=4294967295
+
+[DkDialog]
+deleteFileDialog=false
+deleteFileDialog-answer=16384
+overwriteDialog=false
+overwriteDialog-answer=16384
+saveEditDialog=false
+saveEditDialog-answer=16384
+saveTabsDialog=false
+saveTabsDialog-answer=65536
+
+[DkExplorer]
+Date%20ModifiedHidden=true
+Date%20ModifiedSize=0
+LoadSelected=false
+NameHidden=false
+NameSize=254
+ReadOnly=true
+RootPath=/home/itsdrike
+SizeHidden=true
+SizeSize=0
+TypeHidden=true
+TypeSize=0
+
+[DkFilePreview]
+windowPosition=1
+
+[DkMetaDataHUD]
+keyValues=File.Filename, File.Path, File.Size, Exif.Image.Make, Exif.Image.Model, Exif.Image.DateTime, Exif.Image.ImageDescription, Exif.Photo.ISO, Exif.Photo.FocalLength, Exif.Photo.ExposureTime, Exif.Photo.Flash, Exif.Photo.FNumber
+numColumns=-1
+windowPosition=3
+
+[MetaDataSettings]
+saveExifOrientation=false
+
+[Page%20Extraction%20Plugin]
+Method=0
+
+[SlideShowSettings]
+time=@Variant(\0\0\0\x87@\xa0\0\0)
+
+[SynchronizeSettings]
+checkForUpdates=true
+disableUpdateInteraction=false
+
+[zooming]
+useLevels=false
+zoomLevels="0.0001,0.001,0.01,0.05,0.1,0.125,0.166,0.25,0.333,0.5,0.66,1,1.5,2,3,4,5,6,7,8,12,16,32,64,128"
diff --git a/home/.config/npm/npmrc b/home/.config/npm/npmrc
new file mode 100644
index 0000000..fc84b78
--- /dev/null
+++ b/home/.config/npm/npmrc
@@ -0,0 +1,4 @@
+prefix=${XDG_DATA_HOME}/npm
+cache=${XDG_CACHE_HOME}/npm
+tmp=${XDG_RUNTIME_DIR}/npm
+init-module=${XDG_CONFIG_HOME}/npm/config/npm-init.js
diff --git a/home/.config/pcmanfm/default/pcmanfm.conf b/home/.config/pcmanfm/default/pcmanfm.conf
new file mode 100644
index 0000000..e3ca37a
--- /dev/null
+++ b/home/.config/pcmanfm/default/pcmanfm.conf
@@ -0,0 +1,29 @@
+[config]
+bm_open_method=0
+
+[volume]
+mount_on_startup=1
+mount_removable=1
+autorun=1
+
+[autorun]
+x-content/bootable-media=pcmanfm
+
+[ui]
+always_show_tabs=0
+max_tab_chars=32
+win_width=943
+win_height=502
+splitter_pos=217
+media_in_new_tab=0
+desktop_folder_new_win=0
+change_tab_on_drop=1
+close_on_unmount=1
+focus_previous=0
+side_pane_mode=places
+view_mode=icon
+show_hidden=0
+sort=desc;ascending;
+toolbar=newtab;navigation;home;
+show_statusbar=1
+pathbar_mode_buttons=1
diff --git a/home/.config/pki/.keep b/home/.config/pki/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/home/.config/pypoetry/config.toml b/home/.config/pypoetry/config.toml
new file mode 100644
index 0000000..5fcef8c
--- /dev/null
+++ b/home/.config/pypoetry/config.toml
@@ -0,0 +1,3 @@
+[virtualenvs]
+in-project = true
+prefer-active-python = true
diff --git a/home/.config/shell/aliases b/home/.config/shell/aliases
new file mode 100755
index 0000000..d923be9
--- /dev/null
+++ b/home/.config/shell/aliases
@@ -0,0 +1,298 @@
+#!/bin/sh
+
+# I'm not the greatest typist
+alias sl='ls'
+alias mdkir='mkdir'
+alias soruce='source'
+alias souce='source'
+alias suod='sudo '
+alias sduo='sudo '
+
+# Replacements (adding flags)
+alias cp='cp -iv' # Ask before overwriting, verbose
+alias mv='mv -iv' # Ask before overwriting, verbose
+alias rm='trash-put' # Use trash-cli instead of true removal
+alias rmr='\rm -v' # True rm, verbose (asking here is too annoying)
+alias wget='wget -c' # Resume wget by default
+alias df='df -H' # Show sizes as powers of 1000
+
+# Directory changing
+alias ..='cd ..'
+alias ...='cd ../../'
+alias ....='cd ../../../'
+alias .....='cd ../../../../'
+alias .2='cd ../../'
+alias .3='cd ../../../'
+alias .4='cd ../../../../'
+alias .5='cd ../../../../../'
+
+# Files/Directories utilities
+alias mkdir='mkdir -p'
+alias md='mkdir'
+alias fhere='find . -name'
+alias rr='rmr -r'
+alias rf='rmr -f'
+alias rrf='rmr -rf'
+alias vimdiff='nvim -d'
+
+# Directory listing aliases, defaults to exa, if aviable
+if command -v exa > /dev/null; then
+ alias ls='exa'
+ alias l='exa -glah --classify'
+ alias ll='exa -glah --classify -s=size --group-directories-first -r'
+ alias ldir='exa -glahD'
+ alias tree='exa -Tlagh'
+ alias dotall='exa -hulad .[a-z]*' # Show both dotdirs and dotfiles
+ alias dotfiles='dotall | grep -v ^d' # Show all dotfiles
+ alias dotdirs='dotall | grep --color=never ^d' # Show all dotdirs
+else
+ alias ls='ls --color=auto'
+ alias l='ls -lahX --classify'
+ alias ll='ls -lahX --classify --group-directories-first'
+ alias ldir='ls -lahX --classify | grep --color=never ^d'
+ alias dotall='ls -lahXd .[a-z]*'
+ alias dotfiles='dotall | grep -v ^d'
+ alias dotdirs='dotall | grep --color=never ^d'
+fi
+
+# Config access shortcuts
+alias cfzsh='vim ~/.config/zsh/.zshrc'
+alias cfalias='vim ~/.config/shell/aliases'
+alias cffunctions='vim ~/.config/shell/functions'
+alias cfprofile='vim ~/.config/shell/profile'
+alias cfenvironment='vim ~/.config/shell/environment'
+alias cfenv='cfenvironment'
+alias cfhandlers='vim ~/.config/shell/handlers'
+alias cfprompt='vim ~/.config/shell/prompt'
+alias cfkeybinds='vim ~/.config/shell/keybinds'
+alias cfxprofile='vim ~/.config/x11/xprofile'
+alias cfsxhkd='vim ~/.config/sxhkd/sxhkdrc'
+alias cfkbd='cfsxhkd'
+alias cfbspwm='vim ~/.config/bspwm/bspwmrc'
+alias cfxmonad='vim ~/.config/xmonad/xmonad.hs && xmonad --recompile && xmonad --restart'
+alias cfxmobar='vim ~/.config/xmobar/xmobarrc.hs && ~/.config/xmobar/multi_mon.sh 2'
+alias cftodo='vim ~/Personal/vimwiki/todo.md'
+alias cfnvim='vim ~/.config/nvim'
+alias cfvim='cfnvim'
+
+# z.lua shortcuts
+alias j='z' # for the sake of autojump old habits
+alias zz='z -c' # restrict matches to subdirs of $PWD
+alias zb='z -b' # restrict matches to parent directories
+alias zi='z -I' # cd with interactive fzf selection
+alias zbi='z -b -I' # pick parent directory to cd into with fzf
+
+# Fallbacks
+command -v hd > /dev/null || alias hd='hexdump -C' # Cannonical hex dump; some systems have this symlinked
+command -v md5sum > /dev/null || alias md5sum='md5' # Fallback from `md5sum` to `md5`
+command -v sha1sum > /dev/null || alias sha1sum='shasum' # Fallback from `sha1sum` to `shasum`
+command -v vim > /dev/null && alias vi='vim' # Let vim take precedence over vi
+command -v nvim > /dev/null && alias vi='nvim' && alias vim='nvim' # Let nvim take precedence over vi/vim
+command -v vimtutor > /dev/null || alias vimtutor='nvim -c Tutor' # Let vimtutor fallback to nvim's tutor
+
+# X11 clipboard (either using xclip or xsel, xsel takes precedence if both)
+command -v xclip > /dev/null && alias pbcopy='xclip -selection clipboard'
+command -v xclip > /dev/null && alias pbpaste='xclip -selection clipboard -o'
+command -v xsel > /dev/null && alias pbcopy='xsel --clipboard --input'
+command -v xsel > /dev/null && alias pbpaste='xsel --clipboard --output'
+
+# File validation and manipulation
+alias yamlcheck='python -c "import sys, yaml as y; y.safe_load(open(sys.argv[1]))"' # Validate YAML
+alias jsoncheck='jq "." >/dev/null <' # Validate JSON
+alias urlencode='python2 -c "import sys, urllib as ul; print ul.quote_plus(sys.argv[1]);"' # Encode strings as URLs (space->%20, etc.)
+alias mergepdf='gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=_merged.pdf' # Usage: `mergepdf input{1,2,3}.pdf``
+alias encrypt='gpg -c --no-symkey-cache --cipher-algo AES256' # Encrypt file with AES256 symetric encryption
+alias decrypt='gpg' # For the sake of completeness, include decrypt command to the above, though it's only just gpg alias
+
+# Terminal window swallowing for blocking programs (devour)
+alias xdg-open='devour xdg-open'
+alias mpv='devour mpv'
+alias nomacs='devour nomacs'
+alias pcmanfm='devour pcmanfm'
+alias spotify='devour spotify'
+
+# Regular expressions
+alias reg_email='echo "[a-Z0-9._%-]+@[a-Z0-9.-]+\.[a-Z]{2,10}"'
+alias reg_mac='echo "([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}"'
+alias reg_ipv4='echo "([0-9]{1,3}\.){3}[0-9]{1,3}"'
+alias reg_ipv6='echo "\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*"' # Also catches loopbacks (::1), (for valid matching, it needs to be this long...)
+alias reg_ip='echo "(`reg_ipv4`|`reg_ipv6`)"' # Match both IPv4 and IPv6
+
+# Grep aliases
+alias grep_email='grep -E `reg_email`'
+alias grep_ip='grep -E `reg_ip`'
+alias grep_mac='grep -E `reg_mac`'
+alias massgrep='grep -RHIni'
+
+# Network
+alias ip-show='curl https://ifconfig.co' # Get global IP address
+alias ips="ifconfig -a | grep -oE \"inet6? (addr:)?s?\`reg_ip\`\" | awk '{ sub(/inet6? (addr:)? ?/, \"\"); print }'"
+alias lan-device-scan='nmap -T5 -sP 192.168.0.0-255'
+alias lan-vuln-scan='nmap -sT -O --script vuln 192.168.0.0-255'
+alias ports='netstat -tulanp'
+alias listening-ports='netstat -vtlnp --listening'
+alias ssh-list='ss | grep ssh' # List all SSH connections
+alias serve='python -m http.server' # Serve current directorty as HTTP
+alias reverse-dns='host' # It might be easier to just use `host` though
+alias torify='source torsocks on' # Pass every command via torsocks
+alias untorify='source torsocks off' # Stop passing commands via torsocks
+
+# Firewall aliases (IPTables/UFW)
+alias ipt='iptables' # Shortcut
+alias iptlist='iptables -L -n -v --line-numbers' # All rules
+alias iptlistin='iptables -L INPUT -n -v --line-numbers' # IN rules
+alias iptlistout='iptables -L OUTPUT -n -v --line-numbers' # OUT rules
+alias iptlistfw='iptables -L FORWARD -n -v --line-numbers' # FORWARD rules
+alias ufw-log='journalctl -f -n 100 -g ufw' # Show UFW log entries in system journal
+
+# Kernel actions
+alias kernel-recompile='cd /usr/src/linux && make -j7 && make -j7 modules_install && make install'
+alias kernel-oldconfig='cd /usr/src/linux && make oldconfig'
+alias kernel-configure='cd /usr/src/linux && make menuconfig'
+
+# System actions
+alias sv='systemctl'
+alias pacnew="find / -name '*.pacnew' 2>/dev/null" # Search for all new configurations after pacman update
+alias backup="rsync -avHAXS --delete --filter='dir-merge /.rsync-filter'" # Make full rsync backup, respecting .rsync-filter files for exclusions
+alias upload='curl -F "f:1=<-" ix.io'
+alias upload-journal='sudo journalctl -b -1 | upload' # Upload journalctl from last boot to ix.io
+alias auth-log='journalctl SYSLOG_FACILITY=10 -r'
+alias cpu-stress='for i in $(seq $(getconf _NPROCESSORS_ONLN)); do yes > /dev/null & done' # Run `yes > /dev/null` on all cores as stress test
+alias nvidia='__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia' # Run app with nvidia (on hybrid mode with optimus)
+alias swapout='sudo swapoff -a; sudo swapon -a' # Reset swap (move everything to RAM)
+alias mount-ram='mount -t tmpfs tmpfs' # Mount RAM disk for fast filesystem
+alias screenlock='xset s activate' # Use DPMS to trigger xss-lock and handle screen locking
+
+# System info
+alias meminfo='free -m -l -t'
+alias cpuinfo='lscpu'
+alias batinfo='sudo watch -d -n 2 tlp-stat -b'
+alias battery='cat /sys/class/power_supply/BAT0/capacity'
+alias gpumeminfo='frep -i --color memory /var/log/Xorg.0.log'
+alias journalerr='sudo journalctl -p 3 -xb'
+alias distro='cat /etc/*-release'
+alias diskspace_report="df -P -kHl"
+alias kernel='uname -r'
+
+# System processes
+alias psmem='ps auxf | sort -nr -k 4' # Top memory eaters
+alias psmem10='psmem | head -10' # Top 10 memory eaters
+alias pscpu='ps auxf | sort -nr -k 3' # Top cpu eaters
+alias pscpu10='pscpu | head -10' # Top 10 cpu eaters
+alias psg='ps aux | grep -v grep | grep -i -e VSZ -e' # Get searchable process with nice output
+
+# Time info
+alias now='date +"%T"'
+alias nowtime='now'
+alias nowdate='date +"%d-%m-%Y"'
+alias week='date +%V'
+
+# Cleanup
+alias clean-trash='rm -rf ~/.local/share/Trash/* || echo "Trash already empty"'
+alias clean-downloads='rm -rf ~/Downloads/* || echo "Downloads directory is already empty"'
+alias clean-journal='journalctl --vacuum-size=200M || echo "You have to be root to clean journal"'
+alias clean-pacman='pacman -Sc || echo "You have to be root to clean pacman cache"'
+alias cleanup='clean-trash && clean-down && clean-journal && clean-pacman'
+
+# Git aliases
+alias g='git'
+alias gp='git push'
+alias gpl='git pull'
+alias gf='git fetch'
+alias gs='git status --short --branch'
+alias gss='git status'
+alias ga='git add'
+alias gap='git add --patch'
+alias gc='git commit'
+alias gcm='git commit --message'
+alias gb='git branch'
+alias gch='git checkout'
+alias gchb='git checkout -b'
+alias gd='git diff'
+alias gdc='git diff --cached'
+alias gundo='git reset --soft HEAD~'
+alias gredo="git reset 'HEAD@{1}'"
+
+# Youtube-dl aliases
+alias ytv-best='youtube-dl -f bestvideo+bestaudio'
+alias yta-best='youtube-dl --extract-audio --audio-format best'
+alias yta-mp3='youtube-dl --extract-audio --audio-format mp3'
+alias yta-wav='youtube-dl --extract-audio --audio-format wav'
+
+# Terminal vim-like exits, in case I think the terminal is vim
+alias :q='exit'
+alias :q!='exit'
+alias :wq='exit'
+alias :wq!='exit'
+
+# Shell aliases
+alias reload="exec \$SHELL" # Reload the shell (i.e. invoke as a login shell)
+alias path='echo -e ${PATH//:/\\n}' # Print each PATH entry on a separate line
+alias unsudo='sudo -k' # Reset sudo timeout (sudo will require password)
+alias vimwiki='vim -c VimwikiIndex' # Open vimwiki index
+alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
+alias tty-clock='tty-clock -Ssc' # Terminal clock screensaver
+alias rick='curl -s -L https://raw.githubusercontent.com/ItsDrike/rickrollrc/master/roll.sh| bash' # Terminal rickroll
+alias hist='fc -lt "$HISTTIMEFORMAT" 1'
+alias sudovim='sudoedit'
+
+# If user is not root, pass all commands via sudo/doas
+if [ "$(id -u)" -ne 0 ]; then
+ # Enable aliases to be sudoed/doased
+ # with doas having precedence over sudo if found
+
+ ## Uncomment if you are using autocompletion (is ZSH)
+ #command -v /usr/bin/sudo > /dev/null && alias doas='nocorrect sudo ' && alias sudo='nocorrect sudo '
+ #command -v /usr/bin/doas > /dev/null && alias doas='nocorrect doas ' && alias sudo='nocorrect doas '
+
+ ## if the above is uncommented, comment this
+ command -v /usr/bin/sudo > /dev/null && alias doas='sudo ' && alias sudo='sudo '
+ command -v /usr/bin/doas > /dev/null && alias doas='doas ' && alias sudo='doas '
+fi
+
+# enable color support
+if [ -x /usr/bin/dircolors ]; then
+ (test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)") || eval "$(dircolors -b)"
+ alias dir='dir --color=auto'
+ alias vdir='vdir --color=auto'
+
+ alias grep='grep --color=auto'
+ alias cgrep='grep --color=always'
+ alias fgrep='fgrep --color=auto'
+ alias egrep='egrep --color=auto'
+
+ alias diff='diff --color=auto'
+ alias ip='ip --color=auto'
+
+ # Take advantage of $LS_COLORS for completion as well
+ zstyle ':completion:*' list-colors "${(s.:.)LS_COLORS}"
+fi
+
+# Normalize `open` across Linux, macOS, and Windows.
+# This is needed to make `open` function (see below) cross-platform
+if [ ! "$(uname -s)" = 'Darwin' ]; then
+ if grep -q Microsoft /proc/version; then
+ # Ubuntu on Windows using the Linux subsystem
+ alias open='explorer.exe'
+ else
+ alias open='xdg-open'
+ fi
+fi
+
+# Autogenerate python aliases
+if [ -f ~/.config/shell/py-alias ]; then
+ # shellcheck source=/home/itsdrike/.config/shell/py-alias
+ . "$HOME/.config/shell/py-alias"
+fi
+
+# Functions
+if [ -f ~/.config/shell/functions ]; then
+ # shellcheck source=/home/itsdrike/.config/shell/functions
+ . "$HOME/.config/shell/functions"
+fi
+
+# Extra
+if [ -f ~/.config/shell/extra ]; then
+ # shellcheck source=/home/itsdrike/.config/shell/extra
+ . "$HOME/.config/shell/extra"
+fi
diff --git a/home/.config/shell/environment b/home/.config/shell/environment
new file mode 100755
index 0000000..b1692cf
--- /dev/null
+++ b/home/.config/shell/environment
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+# Environmental variable definitions.
+# This file is only sourced once after login, unlike .zshrc/.bashrc
+#
+# NOTE: This file shouldn't be defined for root account. Sudo
+# will not source it (and neither will it source .zshrc/.zprofile),
+# which means the XDG definitions will be ignored anyway, and
+# defining them may break programs when root is actually logged in.
+
+# Define some variables for POSIX compatibility
+uid="$(id -u)"
+
+# Default programs
+export EDITOR="nvim"
+export BROWSER="firefox"
+export TERMINAL="alacritty"
+export DIFFPROG="nvim -d"
+export FILEMANAGER="pcmanfm"
+
+# XDG Standard paths
+export XDG_CONFIG_HOME="$HOME/.config"
+export XDG_CACHE_HOME="$HOME/.cache"
+export XDG_DATA_HOME="$HOME/.local/share"
+export XDG_RUNTIME_DIR="/run/user/$uid"
+
+# Per-Application XDG settings
+export ZDOTDIR="$XDG_CONFIG_HOME/zsh"
+export XINITRC="$XDG_CONFIG_HOME/x11/xinitrc"
+#export XAUTHORITY="$XDG_RUNTIME_DIR/Xauthority" # This line will break some DMs.
+export LESSHISTFILE="-"
+export GTK2_RC_FILES="$XDG_CONFIG_HOME/gtk-2.0/gtkrc"
+export WGETRC="$XDG_CONFIG_HOME/wget/wgetrc"
+export GNUPGHOME="$XDG_DATA_HOME/gnupg"
+export GOPATH="$XDG_DATA_HOME/go"
+export CARGO_HOME="$XDG_DATA_HOME/cargo"
+export RUSTUP_HOME="$XDG_DATA_HOME/rustup"
+export GRADLE_USER_HOME="$XDG_DATA_HOME/gradle"
+export _JAVA_OPTIONS="-Djava.util.prefs.userRoot=$XDG_CONFIG_HOME/java"
+export NPM_CONFIG_USERCONFIG="$XDG_CONFIG_HOME/npm/npmrc"
+export NUGET_PACKAGES="$XDG_CACHE_HOME/NuGetPackages"
+# Less commonly used applications
+export _ZL_DATA="$XDG_DATA_HOME/zlua"
+export SQLITE_HISTORY="$XDG_DATA_HOME/sqlite_history"
+export WAKATIME_HOME="$XDG_CONFIG_HOME/wakatime"
+export IPYTHONDIR="$XDG_CONFIG_HOME/ipython"
+export PYENV_ROOT="$XDG_DATA_HOME/pyenv"
+export MYPY_CACHE_DIR="$XDG_CACHE_HOME/mypy"
+#export PYLINTHOME="$XDG_CACHE_HOME/pylint"
+#export DOCKER_CONFIG="$XDG_CONFIG_HOME/docker"
+#export CUDA_CACHE_PATH="$XDG_CACHE_HOME/nv"
+
+# Colorful man pages
+# If bat is installed, use it as manpager
+# shellcheck disable=SC2155
+if command -v bat > /dev/null; then
+ export MANPAGER="sh -c 'col -bx | bat -l man -p'"
+else
+ export LESS_TERMCAP_mb="$(printf '%b' '[1;31m')"
+ export LESS_TERMCAP_md="$(printf '%b' '[1;36m')"
+ export LESS_TERMCAP_me="$(printf '%b' '[0m')"
+ export LESS_TERMCAP_so="$(printf '%b' '[01;44;33m')"
+ export LESS_TERMCAP_se="$(printf '%b' '[0m')"
+ export LESS_TERMCAP_us="$(printf '%b' '[1;32m')"
+ export LESS_TERMCAP_ue="$(printf '%b' '[0m')"
+fi
+
+# Other program settings
+export HISTTIMEFORMAT="%Y-%m-%d %T "
+export SUDO_ASKPASS="$HOME/.local/bin/scripts/dmenu/dmenupass"
+export PIPENV_VENV_IN_PROJECT=1 # Force pipenv to create new environments within projects ./.venv
+export XSECURELOCK_SHOW_HOSTNAME=0 # Don't show hostname in xsecurelock
+export XSECURELOCK_SHOW_DATETIME=1 # Show current date and time in xsecurelock
+export QT_QPA_PLATFORMTHEME="qt5ct" # Have QT use theme from qt5ct.
+#export QT_STYLE_OVERRIDE="gtk2" # Have QT use the gtk2 theme (needs aur/qt5-styleplugins)
+
+# Remove irrelevant variables added for posix compatibility
+unset posix
diff --git a/home/.config/shell/extra b/home/.config/shell/extra
new file mode 100755
index 0000000..9f3ffc8
--- /dev/null
+++ b/home/.config/shell/extra
@@ -0,0 +1,245 @@
+#!/usr/bin/env zsh
+
+# ----------------------------------------------------------------
+# Additional aliases
+alias cfextra='vim ~/.config/shell/extra'
+alias cflvim='lvim ~/.config/lvim/config.lua'
+alias cfgit='vim ~/.config/git/config'
+alias cfhypr="vim ~/.config/hypr/hyprland.conf"
+alias cfwaybar='vim ~/.config/waybar/config-hypr'
+alias dotsync='git checkout arch && git push && git checkout gentoo && git merge --ff arch && git push && git checkout arch'
+alias kbsk='setxkbmap sk qwerty'
+alias kbus='setxkbmap us'
+alias update-webpage='ssh webpage "cd /var/www/itsdrike.com; git pull; ./scripts/build.sh"'
+alias octave='octave --quiet'
+alias savekern='cp /proc/vmcore /root/crash.dump'
+alias discord-bump='sleep $((2*60*60)) && notify-send "Bump" "Bump time expired"'
+alias svim='nvim'
+alias vim='lvim'
+alias vpn-home='sudo systemctl stop wg-quick@wgivpn && sudo systemctl start wg-quick@wg0'
+alias vpn-ivpn='sudo systemctl stop wg-quick@wg0 && sudo systemctl start wg-quick@wgivpn'
+alias vpn-wg0='vpn-home'
+alias vpn-wgivpn='vpn-ivpn'
+alias vpn-off='sudo systemctl stop wg-quick@wg0 && sudo systemctl stop wg-quick@wgivpn'
+alias spotify-adblock='env LD_PRELOAD=/usr/lib/spotify-adblock.so spotify'
+alias mono-on='pacmd load-module module-remap-sink sink_name=mono master=2 channels=1'
+alias mono-off='pacmd unload-module module-remap-sink'
+
+# ----------------------------------------------------------------
+# Additional functions
+
+git-uni() {
+ git config --local commit.gpgsign false
+ git config --local user.email "p_vacho@utb.cz"
+ git config --local user.name "Peter Vacho"
+}
+
+dot-sync() {
+ target="$(realpath -s "$1")"
+ if [[ "$target" == "$HOME/"* ]]; then
+ rel_path="$(realpath --relative-to="$HOME" "$target")"
+ dot_target="$dothome/$rel_path"
+ else
+ rel_path="$(realpath --relative-to="/" "$target")"
+ dot_target="$dotroot/$rel_path"
+ fi
+
+ >&2 echo "Would copy $target -> $dot_target"
+ if [[ -d "$target" ]]; then
+ rsync -av --delete "${@:2}" "$target/" "$dot_target"
+ else
+ rsync -av "${@:2}" "$target" "$dot_target"
+ fi
+}
+
+pytemp() {
+ dir="$(mktemp --tmpdir=/tmp -d "tmp.pytemp.XXXXXX")"
+ pushd "$dir" >/dev/null
+ yes "" | poetry init
+ cp ~/Personal/Programming/Python/Templates/GitHub/.flake8 .
+ sed -i 's/project_name/src/' ./.flake8
+ poetry add --dev flake8 black isort pyright # also performs install
+ mkdir ./src
+ touch ./src/__init__.py
+ echo "def main():\n ...\n\n" > ./src/__main__.py
+ echo "if __name__ == \"__main__\":\n main()" >> ./src/__main__.py
+ poetry run lvim +2 -c 'execute "normal $ciw" | startinsert!' ./src/__main__.py
+ popd
+ rm -rf "$dir"
+}
+
+
+setuppy(){
+ cp -r "/home/itsdrike/Personal/Programming/Python/Templates/GitHub" "$1"
+ cd "$1"
+ git init
+ poetry update
+ poetry install
+ echo "TODO" >> .gitignore_local
+ poetry shell
+ # Show all places where we used "project_name", these are expected to be renamed
+ grep -RHIni --exclude-dir=.venv project_name
+}
+
+webpage-put(){
+ scp $@ webpage:/var/www/itsdrike.com/etc
+}
+
+webpage-remove(){
+ sftp webpage:/var/www/itsdrike.com/etc <<< "rm $@"
+}
+
+vidtrim(){
+ if [ $# -ne 3 ]; then
+ echo "Invalid number of parameters passed!"
+ echo "Usage: vidtrim [file name] [start time] [end time]"
+ return 1
+ fi
+ no_ext_name=$1:r
+ ext=$1:e
+ i=1
+ while true; do
+ new_name="${no_ext_name}-trimmed-${i}.${ext}"
+ if [ -e "$new_name" ]; then
+ i=$((i + 1))
+ else
+ break
+ fi
+ done
+
+ ffmpeg -ss "$2" -i "$1" -to "$3" -c copy -copyts "$new_name"
+}
+
+vidmerge(){
+ if [ $# -lt 3 ]; then
+ echo "Invalid number of parameters passed!"
+ echo "Usage: vidmerge [input path 1] [input path 2] [optionally more inputs ...] [output name]"
+ echo "Example: vidmerge . REC-2020-05-.*.mp4 output.mp4"
+ return 1
+ fi
+
+ # Parse the input
+ first_file="$1"
+ files="$2"
+ out="$3"
+ shift; shift; shift
+ # Process extra filenames, in case there's more than 2 to merge
+ while [ $# -gt 0 ]; do
+ files="$files\n$out"
+ out="$1"
+ shift
+ done
+
+ # Prefer MP4Box over ffmpeg if installed
+ # this is benefitial because merging with ffmpeg results in files with
+ # messed up timeline (the file will be a merge product of all given files,
+ # but the timeline will suddenly skip i.e. from 10s to 50s seemlessly, resulting
+ # in proper merge, but with weird timeline info)
+ if ! command -v MP4Box >/dev/null 2>&1; then
+ files="$first_file\n$files"
+ # Create file with all of the file paths to concat for ffmpeg
+ substring="'"
+ if test "${files#*$substring}" != "$files"; then
+ echo "Can't handle files with $substring in their names!"
+ return 1
+ fi
+ loc="files.txt"
+ echo "$files" | while IFS= read -r line; do
+ printf "file '%s'\n" "$line" >> "$loc"
+ done
+
+
+ if ffmpeg -f concat -safe 0 -i "$loc" -c copy "$out"; then
+ rm "$loc"
+ else
+ echo "Ffmpeg failed, check '$loc' file, containing the files passed to ffmpeg"
+ fi
+ else
+ cat_list="$(echo "$files" | xargs -d '\n' printf -- '-cat "%s" ')"
+ cmd="MP4Box -add \"$first_file\" $cat_list \"$out\""
+ echo "$cmd"
+ if eval "$cmd"; then
+ echo "Video merge complete, generated output: $out"
+ else
+ echo "MP4Box failed, used cmd: $cmd"
+ fi
+ fi
+}
+
+vidrot(){
+ if [ $# -ne 2 ]; then
+ echo "Invalid number of parameters passed!"
+ echo "Usage: vidrot [video file] [rotation (0/1/2/3)]"
+ echo "0: cclock_flip (90° counterclockwise and vertical flip)"
+ echo "1: clock (90° clockwise)"
+ echo "2: cclock (90° counterclockwise)"
+ echo "3: clock_flip (90° clockwise and vertical flip)"
+ return 1
+ fi
+ name="$1"
+ rotation="$2"
+ no_ext_name=$name:r
+ ext=$name:e
+ editname="${no_ext_name}-rot.${ext}"
+ ffmpeg -i "$name" -vf "transpose=$rotation" "$editname"
+}
+
+# ----------------------------------------------------------------
+# Additional exports
+export dothome="$HOME/Personal/dotfiles/home"
+export dotroot="$HOME/Personal/dotfiles/root"
+export dotvim="$dothome/.config/nvim"
+
+
+# ----------------------------------------------------------------
+# Pacman/Emerge
+if command -v pacman > /dev/null; then
+ alias pkg-info='pacman -Si' # Info about a package in sync index
+ alias pkg-info-local='pacman -Qi' # Same as above, but for locally installed pkgs
+ alias pkg-file-owner='pacman -F' # Show package that owns given file in sync index
+ alias pkg-file-owner-regex='pacman -Fx' # Same as above, but works with partial names/regex
+ alias pkg-file-owner-local='pacman -Qo' # Same as above, but for locally installed pkgs
+ alias pkg-owned-files='pacman -Fl' # Show all files owned by given package in sync index
+ alias pkg-owned-files-local='pacman -Ql' # Same as above 2, but for locally installed pkgs
+ alias pkg-group-list='pacman -Sg' # List all pkgs that will be installed with a group
+ alias pkg-group-list-local='pacman -Qg' # Same as above, but from locally installed pkgs
+ alias pkg-orphans='pacman -Qtdq'
+
+ alias pkg-get-upgrades='pacman -Syyuw' # Download new pkgs, but don't upgrade them
+ alias pkg-extract='pacman -Syw --cachedir .' # Download given pkg to current directory
+ alias pkg-clean-cache='pacman -Sc' # Remove old packages in pacman cache
+
+ alias pkg-vuln-upgrade="pacman -Sy \"\$(arch-audit --upgradable --quiet | awk '{sub(/>=.+/, \"\"); print}' | paste -s -d ' ')\"" # Upgrade all vulnerable packages, with released fixes
+ alias vuln='arch-audit' # Show vulnerable packages that can be upgraded (Arch Linux)
+
+ # Get fastest mirrors (using reflector)
+ alias mirror="sudo reflector -f 30 -l 30 --number 10 --verbose --save /etc/pacman.d/mirrorlist"
+ alias mirrord="sudo reflector --latest 50 --number 20 --sort delay --save /etc/pacman.d/mirrorlist"
+ alias mirrors="sudo reflector --latest 50 --number 20 --sort score --save /etc/pacman.d/mirrorlist"
+ alias mirrora="sudo reflector --latest 50 --number 20 --sort age --save /etc/pacman.d/mirrorlist"
+fi
+
+if command -v emerge > /dev/null; then
+ if command -v eix > /dev/null; then
+ alias pkg-sync='eix-sync'
+ alias pkg-search='eix'
+ else
+ alias pkg-sync='emerge --sync --quiet=n'
+ alias pkg-search='emerge -s'
+ fi
+ alias pkg-update='emerge --update --deep @world'
+ alias pkg-upgrade='pkg-sync && pkg-update'
+ alias pkg-changed-use='pkg-update --changed-use'
+ alias pkg-recompile-all='emerge -e @world'
+
+ alias pkg-which='equery which'
+ alias pkg-size='equery size'
+ alias pkg-depgraph='equery depgraph'
+ alias pkg-depends='equery depends'
+ alias pkg-check='equery check'
+ alias pkg-uses='equery uses'
+ alias pkg-keywords='equery keywords'
+
+ alias update-conf='dispatch-conf'
+fi
+
diff --git a/home/.config/shell/functions b/home/.config/shell/functions
new file mode 100755
index 0000000..81c8b26
--- /dev/null
+++ b/home/.config/shell/functions
@@ -0,0 +1,291 @@
+#!/bin/sh
+# TODO: Currently, this file isn't entirely POSIX compatible,
+# it will run fine with bash or zsh, however some functions may cause
+# issues with pure POSIX. The fill will however run fine, the errors
+# would only occur if the incompatible functions would be started.
+
+# Show application listening on given port
+port() {
+ sudo netstat -pln | grep "$1" | awk '{print $NF}'
+}
+
+# Create a new directory and enter it
+mkd() {
+ # shellcheck disable=SC2164
+ mkdir -p "$1" && cd "$1";
+}
+
+# `o` with no arguments opens the current directory, otherwise opens the given
+# location
+o() {
+ if [ $# -eq 0 ]; then
+ open .;
+ else
+ open "$@";
+ fi;
+}
+
+# Use bat for nicer git diffs
+batdiff() {
+ git diff --name-only --diff-filter=d | xargs bat --diff
+}
+
+# Determine size of a file or total size of a directory
+dirsize() {
+ if du -b /dev/null > /dev/null 2>&1; then
+ arg=-sbh;
+ else
+ arg=-sh;
+ fi
+ if [[ -n "$*" ]]; then
+ \du $arg -- "$@";
+ else
+ \du $arg .[^.]* ./*;
+ fi;
+}
+
+randmac() {
+ sudo ip link set dev "$1" down
+ sudo macchanger -A "$1"
+ sudo ip link set dev "$1" up
+}
+
+# Go to the root of a git tree
+cdgit () {
+ if [ "$(git rev-parse --is-inside-work-tree > /dev/null 2>&1)" -eq 0 ]; then
+ while ! [ -d .git ]; do
+ cd ..
+ done
+ return 0
+ else
+ echo "Not a git directory"
+ return 1
+ fi
+}
+
+# Create a data URL from a file
+dataurl() {
+ mimeType="$(file -b --mime-type "$1")"
+ if echo "$mimeType" | grep -e "^text/.*$" >/dev/null; then
+ mimeType="${mimeType};charset=utf-8"
+ fi
+ echo "data:${mimeType};base64,$(openssl base64 -in "$1" | tr -d '\n')";
+}
+
+# `tre` is a shorthand for `tree` with hidden files and color enabled, ignoring
+# the `.git` directory, listing directories first. The output gets piped into
+# `less` with options to preserve color and line numbers, unless the output is
+# small enough for one screen.
+tre() {
+ tree -I '.git|node_modules|bower_components' --group-directories-first "$@" | less -FRNX;
+}
+
+
+
+# Show all the names (CNs and SANs) listed in the SSL certificate
+# for a given domain
+getcertnames() {
+ if [ -z "${1}" ]; then
+ echo "ERROR: No domain specified.";
+ return 1;
+ fi;
+
+ domain="${1}";
+ echo "Testing ${domain}…";
+ echo ""; # newline
+
+ tmp=$(echo -e "GET / HTTP/1.0\nEOT" \
+ | openssl s_client -connect "${domain}:443" -servername "${domain}" 2>&1);
+
+ if [[ "${tmp}" = *"-----BEGIN CERTIFICATE-----"* ]]; then
+ certText=$(echo "${tmp}" \
+ | openssl x509 -text -certopt "no_aux, no_header, no_issuer, no_pubkey, \
+ no_serial, no_sigdump, no_signame, no_validity, no_version");
+ echo "Common Name:";
+ echo ""; # newline
+ echo "${certText}" | grep "Subject:" | sed -e "s/^.*CN=//" | sed -e "s/\/emailAddress=.*//";
+ echo ""; # newline
+ echo "Subject Alternative Name(s):";
+ echo ""; # newline
+ echo "${certText}" | grep -A 1 "Subject Alternative Name:" \
+ | sed -e "2s/DNS://g" -e "s/ //g" | tr "," "\n" | tail -n +2;
+ return 0;
+ else
+ echo "ERROR: Certificate not found.";
+ return 1;
+ fi;
+}
+
+# Compare original and gzipped file size
+gz_compare() {
+ origsize=$(wc -c < "$1");
+ gzipsize=$(gzip -c "$1" | wc -c);
+ ratio=$(echo "$gzipsize * 100 / $origsize" | bc -l);
+ printf "orig: %d bytes\n" "$origsize";
+ printf "gzip: %d bytes (%2.2f%%)\n" "$gzipsize" "$ratio";
+}
+
+# Extract almost any archive
+extract() {
+ if [ -z "$1" ]; then
+ # display usage if no parameters given
+ echo "Usage: extract ."
+ echo " extract [path/file_name_2.ext] [path/file_name_3.ext]"
+ return 1
+ else
+ for n in "$@"
+ do
+ if [ -f "$n" ] ; then
+ case "${n%,}" in
+ *.tar.bz2|*.tar.gz|*.tar.xz|*.tbz2|*.tgz|*.txz|*.tar)
+ tar xvf "$n" ;;
+ *.lzma) unlzma ./"$n" ;;
+ *.bz2) bunzip2 ./"$n" ;;
+ *.rar) unrar x -ad ./"$n" ;;
+ *.gz) gunzip ./"$n" ;;
+ *.zip) unzip ./"$n" ;;
+ *.z) uncompress ./"$n" ;;
+ *.7z|*.arj|*.cab|*.chm|*.deb|*.dmg|*.iso|*.lzh|*.msi|*.rpm|*.udf|*.wim|*.xar)
+ 7z x ./"$n" ;;
+ *.xz) unxz ./"$n" ;;
+ *.exe) cabextract ./"$n" ;;
+ *)
+ echo "extract: '$n' - unknown archive method"
+ return 1
+ ;;
+ esac
+ else
+ echo "'$n' - file does not exist"
+ return 1
+ fi
+ done
+fi
+}
+
+# Create a .tar.gz archive, using `zopfli`, `pigz` or `gzip` for compression
+targz() {
+ # Combine given names spearated with spaces as the filename
+ tmpFile="${*%/}.tar"
+
+ tar -cvf "${tmpFile}" "${@}" || return 1
+
+ size=$(
+ stat -f"%z" "${tmpFile}" 2> /dev/null; # macOS `stat`
+ stat -c"%s" "${tmpFile}" 2> /dev/null; # GNU `stat`
+ );
+
+ cmd="";
+ if (( size < 52428800 )) && hash zopfli 2> /dev/null; then
+ # the .tar file is smaller than 50 MB and Zopfli is available; use it
+ cmd="zopfli";
+ else
+ if hash pigz 2> /dev/null; then
+ cmd="pigz";
+ else
+ cmd="gzip";
+ fi;
+ fi;
+
+ echo "Compressing .tar ($((size / 1000)) kB) using \`${cmd}\`…";
+ "${cmd}" -v "${tmpFile}" || return 1;
+ [ -f "${tmpFile}" ] && rm "${tmpFile}";
+
+ zippedSize=$(
+ stat -f"%z" "${tmpFile}.gz" 2> /dev/null; # macOS `stat`
+ stat -c"%s" "${tmpFile}.gz" 2> /dev/null; # GNU `stat`
+ );
+
+ echo "${tmpFile}.gz ($((zippedSize / 1000)) kB) created successfully.";
+}
+
+anonymize() {
+ # Reset the prompt on initial run to allow this script
+ # to be ran multiple times without user having to reload
+ # PS1 manually
+ # shellcheck source=/home/itsdrike/.config/shell/prompt
+ . "${XDG_CONFIG_DIR:-$HOME/.config}/shell/prompt"
+
+ # Regular expression to match 0-255 numbers (color)
+ color_int_re='^(0+)?([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
+
+ # Defaults
+ NAME="%n"
+ MACHINE=""
+ #NAME_COLOR="%F{047}"
+ NAME_COLOR="%F{172}"
+ #DIR_COLOR="%F{027}"
+ DIR_COLOR="%F{158}"
+ AT_COLOR="%F{004}"
+ MACHINE_COLOR="%F{070}"
+
+ while [ $# -gt 0 ]; do
+ key=$1
+
+ case $key in
+ -n|--name)
+ NAME=$2
+ shift
+ shift
+ ;;
+ -m|--machine)
+ MACHINE=$2
+ shift
+ shift
+ ;;
+ -nc|--name-color)
+ if [[ $2 =~ $color_int_re ]]; then
+ NAME_COLOR="%F{$2}"
+ else
+ NAME_COLOR=$2
+ fi
+ shift
+ shift
+ ;;
+ -dc|--dir-color)
+ if [[ $2 =~ $color_int_re ]]; then
+ DIR_COLOR="%F{$2}"
+ else
+ DIR_COLOR=$2
+ fi
+ shift
+ shift
+ ;;
+ -mc|--machine-color)
+ if [[ $2 =~ $color_int_re ]]; then
+ MACHINE_COLOR="%F{$2}"
+ else
+ MACHINE_COLOR=$2
+ fi
+ shift
+ shift
+ ;;
+ -ac|--at-color)
+ if [[ $2 =~ $color_int_re ]]; then
+ AT_COLOR="%F{$2}"
+ else
+ AT_COLOR=$2
+ fi
+ shift
+ shift
+ ;;
+ *)
+ echo "Unrecognized argument: $key"
+ echo "Arguments: -n|--name, -m|--machine, -nc|--name-color, -dc|--dir-color, -mc|--machine-color, -ac|--at-color"
+ return 1
+ ;;
+ esac
+ done
+
+
+ OLD_LINE="%F{047}%n%f %F{027}"
+
+ [ -n "$NAME" ] && NEW_LINE="${NAME_COLOR}${NAME}"
+ [ -n "$NAME" ] && [ -n "$MACHINE" ] && NEW_LINE="${NEW_LINE}${AT_COLOR}@"
+ [ -n "$MACHINE" ] && NEW_LINE="${NEW_LINE}${MACHINE_COLOR}${MACHINE}"
+ [ -n "$NAME" ] || [ -n "$MACHINE" ] && NEW_LINE="${NEW_LINE}%f "
+ NEW_LINE="${NEW_LINE}${DIR_COLOR}"
+
+ # Use new anonymized name, machine and colors in PS1
+ PS1=${PS1/"$OLD_LINE"/"$NEW_LINE"}
+}
+
diff --git a/home/.config/shell/handlers b/home/.config/shell/handlers
new file mode 100755
index 0000000..5434015
--- /dev/null
+++ b/home/.config/shell/handlers
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+if command -v pkgfile > /dev/null; then
+ # Command not found hook that uses `pkgfile` package
+ # to search through the package index in order to find
+ # a package which includes given command, which was resolved
+ # and not found, if there are no such packages, only print
+ # command not found message
+ command_not_found_handler() {
+ cmd="$1"
+ printf 'zsh: command not found: %s' "$cmd" # print command not found asap, then search for packages
+ repos="$(pkgfile "$cmd")"
+ if [ -n "$repos" ]; then
+ printf '\r%s may be found in the following packages:\n' "$cmd"
+ echo "$repos" | while read -r pkg; do
+ printf ' %s\n' "$pkg"
+ done
+ else
+ printf '\n'
+ fi
+ return 127
+ }
+elif [ -x /usr/lib/command-not-found ] || [ -x /usr/share/command-not-found/command-not-found ]; then
+ # Ubuntu handle for bash default command-not-found
+ # it works similarely to the above arch alternative,
+ # this is based on the original bash implementation
+ command_not_found_handler() {
+ # check because cmd not found could've been removed in the meantime
+ if [ -x /usr/lib/command-not-found ]; then
+ /usr/lib/command-not-found -- "$1"
+ return $?
+ elif [ -x /usr/share/command-not-found/command-not-found ]; then
+ /usr/share/command-not-found/command-not-found -- "$1"
+ return $?
+ else
+ printf "%s: command not found\n" "$1" >&2
+ return 127
+ fi
+ }
+fi
diff --git a/home/.config/shell/keybinds b/home/.config/shell/keybinds
new file mode 100755
index 0000000..f95b1cc
--- /dev/null
+++ b/home/.config/shell/keybinds
@@ -0,0 +1,65 @@
+#!/usr/bin/env zsh
+# shellcheck disable=SC2030,SC2031,SC2015
+# Set default keybindings (mostly from oh-my-zsh)
+
+# Make sure that the terminal is in application mode when zle is active, since
+# only then values from $terminfo are valid
+if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
+ function zle-line-init() {
+ echoti smkx
+ }
+ function zle-line-finish() {
+ echoti rmkx
+ }
+ zle -N zle-line-init
+ zle -N zle-line-finish
+fi
+
+# Use emacs keybindings
+bindkey -e
+
+# Start typing + [Up-Arrow] - fuzzy find history forward
+if [ -n "${terminfo[kcuu1]}" ]; then
+ autoload -U up-line-or-beginning-search
+ zle -N up-line-or-beginning-search
+ bindkey "${terminfo[kcuu1]}" up-line-or-beginning-search
+fi
+# Start typing + [Down-Arrow] - fuzzy find history backward
+if [ -n "${terminfo[kcud1]}" ]; then
+ autoload -U down-line-or-beginning-search
+ zle -N down-line-or-beginning-search
+ bindkey "${terminfo[kcud1]}" down-line-or-beginning-search
+fi
+
+# [Home] - Go to beginning of line
+[ -n "${terminfo[khome]}" ] && bindkey "${terminfo[khome]}" beginning-of-line || bindkey "^[[H" beginning-of-line
+# [End] - Go to end of line
+[ -n "${terminfo[kend]}" ] && bindkey "${terminfo[kend]}" end-of-line || bindkey "^[[F" end-of-line
+
+# [Shift-Tab] - move through the completion menu backwards
+[ -n "${terminfo[kcbt]}" ] && bindkey "${terminfo[kcbt]}" reverse-menu-complete
+
+# [Backspace] - delete backward
+bindkey '^?' backward-delete-char
+# [Delete] - delete forward
+[ -n "${terminfo[kdch1]}" ] && bindkey "${terminfo[kdch1]}" delete-char || bindkey "^[[3~" delete-char
+# [Ctrl-Delete] - delete whole forward-word
+bindkey '^[[3;5~' kill-word
+
+# [Ctrl-RightArrow] - move forward one word
+bindkey '^[[1;5C' forward-word
+# [Ctrl-LeftArrow] - move backward one word
+bindkey '^[[1;5D' backward-word
+
+# [Ctrl-r] - Search backward incrementally for a specified string. The string may begin with ^ to anchor the search to the beginning of the line.
+bindkey '^r' history-incremental-search-backward
+# [PageUp] - Up a line of history
+[ -n "${terminfo[kpp]}" ] && bindkey "${terminfo[kpp]}" up-line-or-history
+# [PageDown] - Down a line of history
+[ -n "${terminfo[knp]}" ] && bindkey "${terminfo[knp]}" down-line-or-history
+
+# [Space] - do history expansion on space
+bindkey ' ' magic-space
+
+# [ctrl+space] Accept suggestion from zsh-autosuggestions plugin
+bindkey '^ ' autosuggest-accept
diff --git a/home/.config/shell/profile b/home/.config/shell/profile
new file mode 100755
index 0000000..b48552c
--- /dev/null
+++ b/home/.config/shell/profile
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# User .profile definition.
+# This file is only sourced once, after login, Unlike
+# .zshrc/.bashrc, which will run whenever a new terminal
+# is opened.
+
+# Add all folders in ~/.local/bin into PATH
+# Some window managers require this line to be in profile
+# not in .zshenv
+PATH+=":${$(find ~/.local/bin -type d | tr '\n' ':')%%:}"
+
+# Start graphical session automatically on tty1 if startx is aviable
+if [ "$(tty)" = "/dev/tty1" ] && [ "$UID" != 0 ]; then
+ if command -v Hyprland >/dev/null; then
+ ! pidof -s Hyprland >/dev/null 2>&1 && launch-hypr
+ fi
+fi
+
diff --git a/home/.config/shell/prompt b/home/.config/shell/prompt
new file mode 100755
index 0000000..ca0aaa3
--- /dev/null
+++ b/home/.config/shell/prompt
@@ -0,0 +1,187 @@
+#!/usr/bin/env zsh
+# shellcheck disable=SC2155
+
+# Configuration variables:
+
+# Once we are too deep in the filestructure, we can usually afford to shorten
+# the whole working directory and only print something like ~/.../dir3/dir4/dir5
+# instead of ~/dir1/dir2/dir3/dir4/dir5. If this isn't desired, set this to 0
+USE_SHORTENED_WORKDIR=1
+
+# Show how much time it took to run a command
+CMD_TIME_SHOW=1
+# Minimum units to show the time precision, if
+# we use "s" (seconds), and the output took 0s,
+# we don't print the output at all to avoid clutter.
+# Same goes for any other units, however with "ms"
+# (miliseconds), this is very unlikely
+# Valid options: ms/s/m/h/d
+CMD_TIME_PRECISION="s"
+# Minimum time in miliseconds, to print the time took,
+# if the command takes less than this amount of miliseconds,
+# don't bother printing the time took, this is nice if you
+# don't need to see how long commands like 'echo' took
+# Setting this to 0 will always print the time taken
+CMD_TIME_MINIMUM=100
+
+# hide EOL sign ('%')
+export PROMPT_EOL_MARK=""
+
+# TTY (pure linux) terminal only has 8-bit color support
+# (unless you change it in kernel), respect this and downgrade
+# the color scheme accordingly (it won't look best, but it's
+# still better than no colors)
+if [ "$TERM" = "linux" ]; then
+ GREEN="%F{002}"
+ RED="%F{001}"
+ ORANGE="%F{003}"
+ BLUE="%F{004}"
+ LBLUE="%F{006}"
+ PURPLE="%F{005}"
+else
+ GREEN="%F{047}"
+ RED="%F{196}"
+ ORANGE="%F{214}"
+ BLUE="%F{027}"
+ LBLUE="%F{075}"
+ PURPLE="%F{105}"
+fi
+RESET="%f"
+
+# Signals git status of CWD repository (if any)
+git_prompt() {
+ ref=$(command git symbolic-ref HEAD 2> /dev/null) || ref=$(command git rev-parse --short HEAD 2> /dev/null) || return 0
+ echo -n " $ORANGE${ref#refs/heads/}"
+
+ if [ -n "$(git status --short 2>/dev/null)" ]; then
+ echo "$RED+"
+ fi
+}
+
+# Adds @chroot or @ssh
+foreign_prompt() {
+ if [ "$(awk '$5=="/" {print $1}' /dev/null; then
+ echo ";$full_version;"
+ else
+ echo ';;'
+ fi
+}
+
+# Prints version number extracted from alias for given version
+# $1 - version used in the alias (for example '3.6', '3', or even '', but also 'pypy3.6', ...)
+get_alias_version() {
+ alias_version="$1"
+ definition="$(alias "py$alias_version")"
+ full_version="$(echo "$definition" | cut -d= -f3 | cut -d' ' -f1)"
+
+ version_info="$(parse_python_version "$full_version")"
+ version="$(echo "$version_info" | cut -d';' -f2)"
+ echo "$version"
+}
+
+# Compares 2 python versions in major, minor and micro parts
+# $1 - version #1
+# $2 - version #2
+# Returns:
+# 0 - version #1 is newer
+# 1 - version #2 is newer
+# 2 - versions are equal
+version_compare() {
+ version_1="$1"
+ version_2="$2"
+ # ZSH Only:
+ version_1=("${(@s:.:)version_1}")
+ version_2=("${(@s:.:)version_2}")
+ major_1=$version_1[1]
+ major_2=$version_2[1]
+ minor_1=$version_1[2]
+ minor_2=$version_2[2]
+ micro_1=$version_1[3]
+ micro_2=$version_2[3]
+ # POSIX, but slow:
+ # major_1="$(echo "$version_1" | cut -d. -f1)"
+ # major_2="$(echo "$version_2" | cut -d. -f1)"
+ # minor_1="$(echo "$version_1" | cut -d. -f2)"
+ # minor_2="$(echo "$version_2" | cut -d. -f2)"
+ # micro_1="$(echo "$version_1" | cut -d. -f3)"
+ # micro_2="$(echo "$version_2" | cut -d. -f3)"
+
+ # Compare majors
+ if [ $major_1 -gt $major_2 ]; then
+ # version 1's major is bigger, version 1 is newer
+ return 0
+ elif [ $major_1 -lt $major_2 ]; then
+ # version 1's major is smaller, version 2 is newer
+ return 1
+ fi
+
+ # Majors equal, compare minors
+ if [ $minor_1 -gt $minor_2 ]; then
+ # version 1's minor is bigger, version 1 is newer
+ return 0
+ elif [ $minor_1 -lt $minor_2 ]; then
+ # version 1's major is smaller, version 2 is newer
+ return 1
+ fi
+
+ # Minors equal, compare micros
+ if [ $micro_1 -gt $micro_2 ]; then
+ # version 1's micro is bigger, version 1 is newer
+ return 0
+ elif [ $micro_1 -lt $micro_2 ]; then
+ # version 1's micro is smaller, version 2 is newer
+ return 1
+ fi
+
+ # Micros equal, versions equal
+ return 2
+}
+
+# Define new aliases if they don't already exsist, in which case override
+# if the current version is newer than the version in the alias
+# $1 - full valid pyenv python version (for example '3.6.12', `3.11-dev`, or `pypy3.6-7.2.0-src`)
+# $2 - version used in the alias (for example '3.6', '3', or even '', but also `pypy3.7`, ...)
+try_define_aliases() {
+ version="$1"
+ alias_version="$2"
+
+ # Check if alias already exists
+ if alias "py$alias_version" >/dev/null; then
+ # Compare version from the existing alias with current version,
+ # if current is newer, override the existing alias(es)
+ defined_version="$(get_alias_version "$alias_version")"
+ if version_compare "$version" "$defined_version"; then
+ define_aliases "$version" "$alias_version"
+ # echo "Overwrote '$alias_version' aliases to point to '$version'"
+ return 0
+ else
+ return 1
+ fi
+ fi
+
+ # The aliases aren't already defined, it's safe to create them
+ define_aliases "$version" "$alias_version"
+ # echo "Made '$alias_version' aliases pointing to '$version'"
+ return 0
+}
+
+define_version_aliases() {
+ prefix="$1"
+ version="$2"
+ suffix="$3"
+
+
+ # ZSH only:
+ version_data=("${(@s:.:)version}")
+ major_version=$version_data[1]
+ minor_version=$version_data[2]
+ # POSIX, but slow:
+ # major_version="$(echo "$version" | cut -d. -f1)"
+ # minor_version="$(echo "$version" | cut -d. -f2)"
+
+ # Define the major.minor.micro (full) alias
+ try_define_aliases "$version" "$prefix$version$suffix"
+ # Define the major.minor alias
+ try_define_aliases "$version" "$prefix$major_version.$minor_version$suffix"
+ # Define the major alias
+ try_define_aliases "$version" "$prefix$major_version$suffix"
+ # Define top level alias
+ try_define_aliases "$version" "$prefix$suffix"
+}
+
+for python_dir in "$PYENV_ROOT"/versions/*/ ; do
+ full_version="$(basename $python_dir)"
+
+ version_info="$(parse_python_version "$full_version")"
+ if [ $version_info = ';;' ]; then
+ # Version info wasn't obtained successfully, skip this version
+ echo "Skipped $full_version"
+ continue
+ fi
+
+ # ZSH only:
+ version_data=("${(@s:;:)version_info}")
+ prefix=$version_data[1]
+ version=$version_data[2]
+ suffix=$version_data[3]
+ # POSIX, but slow:
+ # prefix="$(echo "$version_info" | cut -d';' -f1)"
+ # version="$(echo "$version_info" | cut -d';' -f2)"
+ # suffix="$(echo "$version_info" | cut -d';' -f3)"
+
+ # startTime=$(date +%N)
+ define_version_aliases "$prefix" "$version" "$suffix"
+ # endTime=$(date +%N)
+ # nanos="$(expr $endTime - $startTime)"
+ # echo "took $(expr $nanos / 1000000) miliseconds"
+done
+
+if command -v poetry >/dev/null 2>&1; then
+ alias poetry-pyenv='poetry env use "$(pyenv which python)" && poetry install'
+fi
diff --git a/home/.config/swappy/config b/home/.config/swappy/config
new file mode 100644
index 0000000..dbfe13c
--- /dev/null
+++ b/home/.config/swappy/config
@@ -0,0 +1,9 @@
+[Default]
+save_dir=$HOME/Pictures/Screenshots
+save_filename_format=Screenshot_%Y-%M-%D_%H-%M-%S.png
+show_panel=false
+line_size=5
+text_size=20
+text_font=JetBrains Mono
+early_exit=true
+paint_mode=rectangle
diff --git a/home/.config/swayidle/config b/home/.config/swayidle/config
new file mode 100644
index 0000000..958398c
--- /dev/null
+++ b/home/.config/swayidle/config
@@ -0,0 +1,4 @@
+timeout 300 "hyprctl dispatch dpms off" resume "hyprctl dispatch dpms on"
+timeout 310 "loginctl lock-session"
+before-sleep swaylock -fF
+lock swaylock -fF
diff --git a/home/.config/swaylock/config b/home/.config/swaylock/config
new file mode 100644
index 0000000..1f68e36
--- /dev/null
+++ b/home/.config/swaylock/config
@@ -0,0 +1,31 @@
+ignore-empty-password
+clock
+
+color=1d1f21
+indicator-idle-visible
+indicator-radius=150
+indicator-thickness=30
+
+inside-color=1d1f21
+inside-clear-color=1d1f21
+inside-ver-color=1d1f21
+inside-wrong-color=1d1f21
+
+key-hl-color=7aa6daaa
+bs-hl-color=d54e53aa
+
+separator-color=55555555
+
+line-color=1d1f21
+line-uses-ring
+
+text-color=81a2be
+text-clear-color=b5bd68
+text-caps-lock-color=f0c674
+text-ver-color=81a2be
+text-wrong-color=cc6666
+
+ring-color=81a2be55
+ring-ver-color=81a2be
+ring-clear-color=b5bd6811
+ring-wrong-color=cc6666
diff --git a/home/.config/user-dirs.dirs b/home/.config/user-dirs.dirs
new file mode 100644
index 0000000..52196bb
--- /dev/null
+++ b/home/.config/user-dirs.dirs
@@ -0,0 +1,17 @@
+# This file is written by xdg-user-dirs-update
+# If you want to change or add directories, just edit the line you're
+# interested in. All local changes will be retained on the next run.
+# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
+# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
+# absolute path. No other format is supported.
+#
+#XDG_DESKTOP_DIR="$HOME/Desktop"
+XDG_DOWNLOAD_DIR="$HOME/Downloads"
+#XDG_TEMPLATES_DIR="$HOME/Templates"
+#XDG_PUBLICSHARE_DIR="$HOME/Public"
+#XDG_DOCUMENTS_DIR="$HOME/Documents"
+XDG_DOCUMENTS_DIR="$HOME/Personal"
+#XDG_MUSIC_DIR="$HOME/Music"
+XDG_MUSIC_DIR="$HOME/Audio"
+XDG_PICTURES_DIR="$HOME/Pictures"
+#XDG_VIDEOS_DIR="$HOME/Videos"
diff --git a/home/.config/user-dirs.locale b/home/.config/user-dirs.locale
new file mode 100644
index 0000000..3e0b419
--- /dev/null
+++ b/home/.config/user-dirs.locale
@@ -0,0 +1 @@
+en_US
\ No newline at end of file
diff --git a/home/.config/waybar/config-hypr b/home/.config/waybar/config-hypr
new file mode 100644
index 0000000..62bfd1b
--- /dev/null
+++ b/home/.config/waybar/config-hypr
@@ -0,0 +1,146 @@
+// vi: ft=json
+
+{
+ "layer": "top",
+ "position": "top",
+ "height": 20,
+
+ "modules-left": ["idle_inhibitor", "custom/gammastep", "hyprland/window"],
+ "modules-center": ["wlr/workspaces"],
+ "modules-right": ["pulseaudio", "pulseaudio#mic", "network#vpn", "network", "battery", "cpu", "memory", "clock", "tray"],
+
+ "hyprland/window": {
+ "format": "{}",
+ "max-length": 70,
+ "separate-outputs": true,
+ "rewrite": {
+ "": "\uf015",
+ "(.*) — Mozilla Firefox": "\uf269 $1",
+ "Mozilla Firefox": "\uf269 Mozilla Firefox",
+ "Alacritty": "\uf120 Alacritty",
+ "(?:zsh;#toggleterm#1 - )?(.*) - N?VIM": "\uf15c $1",
+ "/(.*)": "\uf07b /$1",
+ "(.*) - mpv": "\uf03d $1",
+ "(.*) - Discord": "\uf392 $1",
+ "Stremio - (.*)": "\uf008 Stremio - $1",
+ "pulsemixer": "\uf001 Pulsemixer",
+ "Spotify": "\uf1bc Spotify",
+ }
+ },
+
+ "wlr/workspaces": {
+ "format": "{icon}",
+ "on-click": "activate",
+ "all-outputs": true,
+ "format-icons": {
+ "1": "",
+ "2": "",
+ "3": "",
+ "4": "",
+ "5": "",
+ "6": "",
+ "7": "7",
+ "8": "8",
+ "9": "9",
+ "urgent": "",
+ }
+ },
+
+ "idle_inhibitor": {
+ "format": "{icon}",
+ "format-icons": {
+ "activated": "",
+ "deactivated": ""
+ }
+ },
+
+ "tray": {
+ "spacing": 10,
+ "show-passive-items": true
+ },
+
+ "clock": {
+ "format": "{:\uf017 %e %b %H:%M}",
+ "format-alt": "{:\uf133 %A, %d %B, %Y}",
+ "tooltip-format": "{:%d %B, %Y}\n{calendar}"
+ },
+
+
+ "battery": {
+ "states": {
+ "warning": 30,
+ "critical": 15
+ },
+ "bat": "BAT0",
+ "adapter": "ADP0",
+ "format": "{icon} {capacity}%",
+ "format-charging": " {capacity}%",
+ "format-plugged": " {capacity}%",
+ "format-alt": "{icon} {time}",
+ "format-full": "",
+ "format-icons": ["", "", "", "", ""]
+ },
+
+ "network": {
+ "interval": 5,
+ "format-wifi": "\uf1eb",
+ "format-ethernet": "\uf796",
+ "format-disconnected": "\uf127 Offline",
+ "tooltip-format": "{ifname}: {ipaddr}",
+ "tooltip-format-wifi": "{essid} ({signalStrength}%): {ipaddr}"
+ },
+ "network#vpn": {
+ "interval": 5,
+ "interface": "wgivpn",
+ "format": "\uf3ed",
+ "format-disconnected": "",
+ "tooltip-format": "VPN Connected: {ipaddr}"
+ },
+
+ "pulseaudio": {
+ "scroll-step": 1,
+ "format": "{icon} {volume}%",
+ "format-bluetooth": "{icon} {volume}%",
+ "format-bluetooth-muted": "{icon} ",
+ "format-muted": "",
+ "format-source": "",
+ "format-source-muted": "",
+ "format-icons": {
+ "headphone": "",
+ "hands-free": "",
+ "headset": "",
+ "phone": "",
+ "portable": "",
+ "car": "",
+ "default": ["", "", ""]
+ },
+ "on-click": "pkill pulsemixer; alacritty -e pulsemixer"
+ },
+ "pulseaudio#mic": {
+ "format": "{format_source}",
+ "format-source": "",
+ "format-source-muted": "",
+ "on-click": "pactl set-source-mute @DEFAULT_SOURCE@ toggle",
+ "tooltip": false
+ },
+
+ "custom/gammastep": {
+ "format": "{}",
+ "interval": 5,
+ "on-update": "",
+ "exec": "sleep 0.05; gammastep-ctl",
+ "on-click": "gammastep-ctl toggle"
+ },
+
+ "memory": {
+ "interval": 30,
+ "format": " {used:0.1f}G: {percentage}%",
+ },
+
+ "cpu": {
+ "interval": 10,
+ "format": " {}%",
+ "max-length": 10
+ }
+
+}
diff --git a/home/.config/waybar/config-hypr.bak b/home/.config/waybar/config-hypr.bak
new file mode 100644
index 0000000..dc9801b
--- /dev/null
+++ b/home/.config/waybar/config-hypr.bak
@@ -0,0 +1,159 @@
+{
+ "layer": "top", // Waybar at top layer
+ "position": "top", // Waybar position (top|bottom|left|right)
+ "height": 30, // Waybar height (to be removed for auto height)
+ // "width": 1280, // Waybar width
+ "spacing": 4, // Gaps between modules (4px)
+ // Choose the order of the modules
+ "modules-left": ["wlr/workspaces"],
+ "modules-center": ["sway/window"],
+ "modules-right": ["idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "keyboard-state", "sway/language", "battery", "battery#bat2", "clock", "tray"],
+ // Modules configuration
+ // "sway/workspaces": {
+ // "disable-scroll": true,
+ // "all-outputs": true,
+ // "format": "{name}: {icon}",
+ // "format-icons": {
+ // "1": "",
+ // "2": "",
+ // "3": "",
+ // "4": "",
+ // "5": "",
+ // "urgent": "",
+ // "focused": "",
+ // "default": ""
+ // }
+ // },
+ "keyboard-state": {
+ "numlock": true,
+ "capslock": true,
+ "format": "{name} {icon}",
+ "format-icons": {
+ "locked": "",
+ "unlocked": ""
+ }
+ },
+ "sway/mode": {
+ "format": "{}"
+ },
+ "mpd": {
+ "format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ⸨{songPosition}|{queueLength}⸩ {volume}% ",
+ "format-disconnected": "Disconnected ",
+ "format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ",
+ "unknown-tag": "N/A",
+ "interval": 2,
+ "consume-icons": {
+ "on": " "
+ },
+ "random-icons": {
+ "off": " ",
+ "on": " "
+ },
+ "repeat-icons": {
+ "on": " "
+ },
+ "single-icons": {
+ "on": "1 "
+ },
+ "state-icons": {
+ "paused": "",
+ "playing": ""
+ },
+ "tooltip-format": "MPD (connected)",
+ "tooltip-format-disconnected": "MPD (disconnected)"
+ },
+ "idle_inhibitor": {
+ "format": "{icon}",
+ "format-icons": {
+ "activated": "",
+ "deactivated": ""
+ }
+ },
+ "tray": {
+ // "icon-size": 21,
+ "spacing": 10
+ },
+ "clock": {
+ // "timezone": "America/New_York",
+ "tooltip-format": "{:%Y %B}\n{calendar}",
+ "format-alt": "{:%Y-%m-%d}"
+ },
+ "cpu": {
+ "format": "{usage}% ",
+ "tooltip": false
+ },
+ "memory": {
+ "format": "{}% "
+ },
+ "temperature": {
+ // "thermal-zone": 2,
+ // "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
+ "critical-threshold": 80,
+ // "format-critical": "{temperatureC}°C {icon}",
+ "format": "{temperatureC}°C {icon}",
+ "format-icons": ["", "", ""]
+ },
+ "backlight": {
+ // "device": "acpi_video1",
+ "format": "{percent}% {icon}",
+ "format-icons": ["", "", "", "", "", "", "", "", ""]
+ },
+ "battery": {
+ "states": {
+ // "good": 95,
+ "warning": 30,
+ "critical": 15
+ },
+ "format": "{capacity}% {icon}",
+ "format-charging": "{capacity}% ",
+ "format-plugged": "{capacity}% ",
+ "format-alt": "{time} {icon}",
+ // "format-good": "", // An empty format will hide the module
+ // "format-full": "",
+ "format-icons": ["", "", "", "", ""]
+ },
+ "battery#bat2": {
+ "bat": "BAT2"
+ },
+ "network": {
+ // "interface": "wlp2*", // (Optional) To force the use of this interface
+ "format-wifi": "{essid} ({signalStrength}%) ",
+ "format-ethernet": "{ipaddr}/{cidr} ",
+ "tooltip-format": "{ifname} via {gwaddr} ",
+ "format-linked": "{ifname} (No IP) ",
+ "format-disconnected": "Disconnected ⚠",
+ "format-alt": "{ifname}: {ipaddr}/{cidr}"
+ },
+ "pulseaudio": {
+ // "scroll-step": 1, // %, can be a float
+ "format": "{volume}% {icon} {format_source}",
+ "format-bluetooth": "{volume}% {icon} {format_source}",
+ "format-bluetooth-muted": " {icon} {format_source}",
+ "format-muted": " {format_source}",
+ "format-source": "{volume}% ",
+ "format-source-muted": "",
+ "format-icons": {
+ "headphone": "",
+ "hands-free": "",
+ "headset": "",
+ "phone": "",
+ "portable": "",
+ "car": "",
+ "default": ["", "", ""]
+ },
+ "on-click": "pavucontrol"
+ },
+ "custom/media": {
+ "format": "{icon} {}",
+ "return-type": "json",
+ "max-length": 40,
+ "format-icons": {
+ "spotify": "",
+ "default": "🎜"
+ },
+ "escape": true,
+ "exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder
+ // "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name
+ }
+}
+
diff --git a/home/.config/waybar/style.css b/home/.config/waybar/style.css
new file mode 100644
index 0000000..873768b
--- /dev/null
+++ b/home/.config/waybar/style.css
@@ -0,0 +1,136 @@
+* {
+ border: none;
+ border-radius: 0;
+ font-family: "JetBrains Mono", "Font Awesome 6 Free";
+ font-size: 14px;
+}
+
+window .modules-left,
+window .modules-center,
+window .modules-right {
+ background: rgba(55, 59, 65, 0.85);
+ padding: 0px 8px 0px 8px;
+}
+
+window .modules-left {
+ border-top-right-radius: 16px;
+ border-bottom-right-radius: 16px;
+}
+
+window .modules-right {
+ border-top-left-radius: 16px;
+ border-bottom-left-radius: 16px;
+}
+
+window .modules-center {
+ border-radius: 16px;
+}
+window#waybar {
+ background: transparent;
+}
+
+window > box {
+ margin: 5px 0px 5px 0px;
+ padding: 0px 0px 0px 0px;
+ background: rgba(43, 48, 59, 0);
+ color: white;
+ border-radius: 16px;
+ min-height: 32px;
+}
+
+#workspaces button {
+ font-weight: bolder;
+ margin: 3px;
+ padding: 0px 2px 0px 2px;
+ background-color: transparent;
+ color: rgba(255, 255, 255, 0.5);
+ min-width: 24px;
+ box-shadow: inset 0 -3px transparent;
+}
+
+/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
+#workspaces button:hover {
+ background: transparent;
+ box-shadow: inset 0 -3px transparent;
+ color: rgba(255, 255, 255, 0.8);
+}
+
+#workspaces button.active,
+#workspaces button.focused {
+ background: transparent;
+ box-shadow: inset 0 -3px #ffffff;
+ color: rgba(255, 255, 255, 1);
+}
+
+#workspaces button.urgent {
+ box-shadow: inset 0 -3px #cc6666;
+ color: #cc6666;
+}
+
+#clock,
+#battery,
+#cpu,
+#memory,
+#disk,
+#temperature,
+#backlight,
+#network,
+#pulseaudio,
+#custom-media,
+#tray,
+#mode,
+#idle_inhibitor,
+#mpd,
+#window,
+#workspaces,
+#custom-gammastep
+{
+ padding: 0px 8px 0px 8px;
+ margin: 0 5px;
+ color: #ffffff;
+}
+
+#mode {
+ font-weight: bolder;
+ color: #f0c674;
+}
+
+#mpd.stopped {
+ color: rgba(255, 255, 255, 0.3);
+}
+
+#idle_inhibitor.deactivated {
+ color: rgba(255, 255, 255, 0.3);
+}
+
+#network.disconnected, #network.disabled {
+ color: rgba(255, 255, 255, 0.3);
+}
+
+#clock {
+ font-weight: bolder;
+}
+
+@keyframes blink {
+ to {
+ color: #ffffff;
+ }
+}
+
+#battery.critical:not(.charging) {
+ /* background-color: #f53c3c; */
+ color: #ffffff;
+ animation-name: blink;
+ animation-duration: 0.5s;
+ animation-timing-function: linear;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+}
+
+#tray > .passive {
+ -gtk-icon-effect: dim;
+}
+
+#tray > .needs-attention {
+ -gtk-icon-effect: highlight;
+}
diff --git a/home/.config/wget/wgetrc b/home/.config/wget/wgetrc
new file mode 100644
index 0000000..4fd7999
--- /dev/null
+++ b/home/.config/wget/wgetrc
@@ -0,0 +1 @@
+hsts-file=~/.cache/wget-hsts
diff --git a/home/.config/wireplumber/main.lua.d/51-device-rename.lua b/home/.config/wireplumber/main.lua.d/51-device-rename.lua
new file mode 100644
index 0000000..27cdaf9
--- /dev/null
+++ b/home/.config/wireplumber/main.lua.d/51-device-rename.lua
@@ -0,0 +1,59 @@
+
+table.insert(
+ alsa_monitor.rules,
+ {
+ matches = {
+ {
+ { "node.name", "equals", "alsa_output.pci-0000_05_00.6.analog-stereo" },
+ },
+ },
+ apply_properties = {
+ ["node.description"] = "Laptop-output",
+ },
+ }
+)
+
+table.insert(
+ alsa_monitor.rules,
+ {
+ matches = {
+ {
+ { "node.name", "equals", "alsa_input.pci-0000_05_00.6.analog-stereo" },
+ },
+ },
+ apply_properties = {
+ ["node.description"] = "Laptop-input",
+ },
+ }
+)
+
+
+table.insert(
+ alsa_monitor.rules,
+ {
+ matches = {
+ {
+ { "node.name", "equals", "alsa_input.usb-C-Media_Electronics_Inc._Bloody_Gaming_Audio_Device-00.analog-stereo" },
+ },
+ },
+ apply_properties = {
+ ["node.description"] = "Bloody_Gaming_Headphones-input",
+ },
+ }
+)
+
+
+table.insert(
+ alsa_monitor.rules,
+ {
+ matches = {
+ {
+ { "node.name", "equals", "alsa_output.usb-C-Media_Electronics_Inc._Bloody_Gaming_Audio_Device-00.analog-stereo" },
+ },
+ },
+ apply_properties = {
+ ["node.description"] = "Bloody_Gaming_Headphones-output",
+ },
+ }
+)
+
diff --git a/home/.config/wofi/config b/home/.config/wofi/config
new file mode 100644
index 0000000..9217ff5
--- /dev/null
+++ b/home/.config/wofi/config
@@ -0,0 +1,7 @@
+width=40%
+height=30%
+show=drun
+prompt=Search
+allow_images=true
+allow_markup=true
+insensitive=true
diff --git a/home/.config/wofi/style.css b/home/.config/wofi/style.css
new file mode 100644
index 0000000..0ef36a6
--- /dev/null
+++ b/home/.config/wofi/style.css
@@ -0,0 +1,51 @@
+window {
+ font-family: "DejaVu Sans", "Font Awesome 5 Free";
+ margin: 0px;
+ border: 1px solid rgba(0, 0, 0, 0.9);
+ background-color: rgba(29, 31, 33, 0.95);
+ border-radius: 10px;
+}
+
+#input {
+ margin: 5px;
+ border: none;
+ color: #f8f8f2;
+ background-color: rgba(55, 59, 65, 0.95);
+}
+
+#inner-box {
+ margin: 5px;
+ border: none;
+ background-color: transparent;
+}
+
+#outer-box {
+ margin: 5px;
+ border: none;
+ background-color: transparent;
+}
+
+#scroll {
+ margin: 0px;
+ border: none;
+}
+
+#text {
+ margin: 5px;
+ border: none;
+ color: #c5c8c6;
+}
+
+#entry {
+ border: none;
+}
+
+#entry:focus {
+ border: none;
+}
+
+#entry:selected {
+ background-color: rgba(55, 59, 65, 0.95);
+ border-radius: 5px;
+ border: none;
+}
diff --git a/home/.config/zsh/.zprofile b/home/.config/zsh/.zprofile
new file mode 120000
index 0000000..5046066
--- /dev/null
+++ b/home/.config/zsh/.zprofile
@@ -0,0 +1 @@
+../shell/profile
\ No newline at end of file
diff --git a/home/.config/zsh/.zshenv b/home/.config/zsh/.zshenv
new file mode 120000
index 0000000..d8e764c
--- /dev/null
+++ b/home/.config/zsh/.zshenv
@@ -0,0 +1 @@
+../shell/environment
\ No newline at end of file
diff --git a/home/.config/zsh/.zshrc b/home/.config/zsh/.zshrc
new file mode 100755
index 0000000..9182e4b
--- /dev/null
+++ b/home/.config/zsh/.zshrc
@@ -0,0 +1,75 @@
+#!/usr/bin/zsh
+
+# ZSH Options
+setopt auto_cd # cd by typing directory name if it's not a command
+setopt auto_list # automatically list choices on ambiguous completion
+setopt auto_menu # automatically use menu completion
+setopt always_to_end # move cursor to end if word had one match
+setopt interactivecomments # allow comments in interactive mode
+setopt magicequalsubst # enable filename expansion for arguments of form `x=expression`
+setopt notify # report the status of background jobs immediately
+setopt numericglobsort # sort filenames numerically when it makes sense
+setopt auto_pushd # Make cd act as pushd
+#setopt correct_all # autocorrect commands
+
+# oh-my-zsh configuration (DISABLED by default, if you want oh-my-zsh, uncomment these)
+#export ZSH="/usr/share/oh-my-zsh"
+#ZSH_THEME="af-magic"
+#UPDATE_ZSH_DAYS=8
+#ENABLE_CORRECTION="false"
+#source $ZSH/oh-my-zsh.sh # Run oh-my-zsh
+
+# ZSH files setup (don't clutter home)
+export ZSH_CACHE="$HOME/.cache/zsh"
+export HISTFILE="$ZSH_CACHE/history"
+export ZSH_COMPDUMP="$ZSH_CACHE/zcompdump-$ZSH_VERSION"
+mkdir -p "$ZSH_CACHE"
+
+# Auto-remove home clutter
+[ -f ~/.zsh-update ] && mv ~/.zsh-update $ZSH_CACHE/.zsh-update
+[ -f ~/.sudo_as_admin_sucessful ] && rm ~/.sudo_as_admin_successful
+[ -f ~/.bash_history ] && rm ~/.bash_history
+
+# History configuration
+export HISTSIZE=10000
+export SAVEHIST=10000
+setopt appendhistory # save history entries as soon as they are entered
+setopt hist_ignore_space # ignore commands that start with space
+setopt hist_verify # show commands with history expansion to user before running it
+setopt extended_history # record command start time
+#setopt hist_ignore_dups # ignore duplicated commands history list
+#setopt hist_expire_dups_first # delete duplicates first when HISTFILE size exceeds HISTFILE
+#setopt share_history # share command history data between terminals
+
+# Completion features (tab)
+autoload -Uz compinit
+zmodload -i zsh/complist # load completion list
+compinit -d $ZSH_COMPDUMP # Specify compdump file
+comp_options+=(globdots) # Enable completion on hidden files.
+zstyle ':completion:*' menu select # select completions with arrow keys
+zstyle ':completion:*' group-name '' # group results by category
+zstyle ':completion:::::' completer _expand _complete _ignored _approximate #enable approximate matches for completion
+
+# Color support
+#autoload -U colors && colors
+
+# Setup aliases
+[ -f ~/.config/shell/aliases ] && source ~/.config/shell/aliases
+# Load handlers
+[ -f ~/.config/shell/handlers ] && source ~/.config/shell/handlers
+# Load key bindings
+[ -f ~/.config/shell/keybinds ] && source ~/.config/shell/keybinds
+# Load prompt
+[ -f ~/.config/shell/prompt ] && source ~/.config/shell/prompt
+
+# Define TMOUT timeout for TTY and root
+[ -z "$DISPLAY" ] && export TMOUT=800
+[ $UID -eq 0 ] && export TMOUT=600
+
+# Load extensions (should be last)
+source /usr/share/zsh/site-functions/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
+source /usr/share/zsh/site-functions/zsh-autosuggestions/zsh-autosuggestions.zsh
+source /usr/local/src/z.lua/z.lua.plugin.zsh
+if command -v pyenv >/dev/null 2>&1; then
+ eval "$(pyenv init -)"
+fi
diff --git a/home/.local/bin/npm/lib/.keep b/home/.local/bin/npm/lib/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/home/.local/bin/scripts/cli/bitcoin b/home/.local/bin/scripts/cli/bitcoin
new file mode 100755
index 0000000..d5547e8
--- /dev/null
+++ b/home/.local/bin/scripts/cli/bitcoin
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+BTC_DATA=$(curl https://api.coindesk.com/v1/bpi/currentprice.json 2>/dev/null || echo 'ERR')
+
+if [ "$BTC_DATA" != "ERR" ]; then
+ BTC_PRICE=$(echo $BTC_DATA | jq -r ".bpi.USD.rate_float")
+ BTC_PRICE=$(printf "%.0f" "$BTC_PRICE")
+ echo \$"$BTC_PRICE"
+else
+ echo "N/A"
+fi
+
diff --git a/home/.local/bin/scripts/cli/cheat.sh b/home/.local/bin/scripts/cli/cheat.sh
new file mode 100755
index 0000000..38bbdf9
--- /dev/null
+++ b/home/.local/bin/scripts/cli/cheat.sh
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+# rm_trailing_slashes(string)
+#
+# Prints a string without any trailing slashes.
+# This is used because cheat.sh doesn't play nicely with multiple slashes in
+# URLs.
+rm_trailing_slashes() {
+ string="$1"
+ last_char="$(printf "$string" | tail -c 1)"
+ if [ "$last_char" = "/" ]; then
+ echo "$(rm_trailing_slashes "${string%?}")"
+ else
+ echo "$string"
+ fi
+}
+
+# pick_category(must_match, query, argument, recurse)
+#
+# Pick cheat.sh category.
+# if must_match is 1, only allow listed options to be picked.
+# if query is specified, pick sub-category of it, else pick global categories.
+# if argument is specified, optionally perform must_match check and print it.
+# if recurse is 1, if the selected option ends with /, run the function again.
+#
+# Prints the chosen category
+pick_category() {
+ must_match="$1"
+ query="$(rm_trailing_slashes "$2")"
+ argument="$3"
+ recurse="$4"
+
+ # Query all possible options
+ if [ -n "$query" ]; then
+ url="cheat.sh/$query/:list"
+ else
+ url="cheat.sh/:list"
+ fi
+ selectable="$(curl -s "$url")"
+
+ # If argument is specified, print it, optionally perform must_match check.
+ if [ -n "$argument" ]; then
+ if [ "$must_match" -ne 1 ] || echo "$selectable" | grep -qe "\b$1\b"; then
+ selected="$argument"
+ else
+ echo "Invalid selection: '$argument'"
+ echo "For all selections, query $url"
+ exit 1
+ fi
+ # Select the option with fzf, optionally allow other matches if must_match isn't set.
+ else
+ if [ "$must_match" -ne 1 ]; then
+ if [ -z "$selectable" ]; then
+ header="No selections found, you can use empty query to show category help, or type a custom query."
+ else
+ header="Use alt-enter to enter non-listed query. You can use empty queries to show category help."
+ fi
+ selected="$(printf "\n$selectable" | \
+ fzf --bind=alt-enter:print-query \
+ --print-query \
+ --prompt="cheat.sh/$query query>" \
+ --header="$header"\
+ )"
+ else
+ selected=$(printf "$selectable" | fzf --prompt="cheat.sh/$query category>")
+ if [ $? -ne 0 ]; then
+ echo "Invalid selection: '$selected'"
+ echo "For all selections, query $url"
+ exit 1
+ fi
+ fi
+ selected=$(printf "$selected" | tail -1)
+ fi
+
+
+ # Replace spaces with '+' (cheat.sh resolves those as spaces)
+ selected="$(echo "$selected" | tr ' ' '+')"
+
+ # Prepend the original query, if we have one
+ # Print the selected category, or subcategory with the category
+ if [ -n "$query" ]; then
+ result="$query/$selected"
+ else
+ result="$selected"
+ fi
+
+ # Recurse, if specified and the result ended with /
+ if [ "$recurse" -eq 1 ]; then
+ if [ "$(printf "$selected" | tail -c 1)" = "/" ]; then
+ result="$(pick_category "$must_match" "$result" "$argument" 1)"
+ fi
+ fi
+
+ # Print the result
+ printf "$result"
+}
+
+# Select the cheatsheat category (language/core-util/...)
+query=$(pick_category 1 "" "$1" 0)
+
+# If the query isn't already complete, select a sub-category
+if ! echo "$query" | grep -qe ":"; then
+ query="$(pick_category 0 "$query" "$2" 1)"
+fi
+
+# Construct the URL from given query and print it
+url="cheat.sh/$query"
+echo "$url"
+
+# Show the output of cheat.sh request
+curl -s "$url"
diff --git a/home/.local/bin/scripts/cli/colors-256 b/home/.local/bin/scripts/cli/colors-256
new file mode 100755
index 0000000..109fba1
--- /dev/null
+++ b/home/.local/bin/scripts/cli/colors-256
@@ -0,0 +1,102 @@
+#!/bin/bash
+
+# # Print out 256 colors, with each number printed in its corresponding colour
+#
+# This file is uploaded on
+# It was originally intended to be used as an alias that curled this URL and piped it into bash, however
+# this is very unsafe as the owner can change the content of this gist at his convenience, meaning it was
+# a potential security vulnerability. This is a script version of this alias to avoid this issue.
+#
+# The copyright for this file belongs to the original author: Tom Hale, 2016
+# This file was released under MIT license
+
+set -eu # Fail on errors or undeclared variables
+
+printable_colours=256
+
+# Return a colour that contrasts with the given colour
+# Bash only does integer division, so keep it integral
+function contrast_colour {
+ local r g b luminance
+ colour="$1"
+
+ if (( colour < 16 )); then # Initial 16 ANSI colours
+ (( colour == 0 )) && printf "15" || printf "0"
+ return
+ fi
+
+ # Greyscale # rgb_R = rgb_G = rgb_B = (number - 232) * 10 + 8
+ if (( colour > 231 )); then # Greyscale ramp
+ (( colour < 244 )) && printf "15" || printf "0"
+ return
+ fi
+
+ # All other colours:
+ # 6x6x6 colour cube = 16 + 36*R + 6*G + B # Where RGB are [0..5]
+ # See http://stackoverflow.com/a/27165165/5353461
+
+ # r=$(( (colour-16) / 36 ))
+ g=$(( ((colour-16) % 36) / 6 ))
+ # b=$(( (colour-16) % 6 ))
+
+ # If luminance is bright, print number in black, white otherwise.
+ # Green contributes 587/1000 to human perceived luminance - ITU R-REC-BT.601
+ (( g > 2)) && printf "0" || printf "15"
+ return
+
+ # Uncomment the below for more precise luminance calculations
+
+ # # Calculate percieved brightness
+ # # See https://www.w3.org/TR/AERT#color-contrast
+ # # and http://www.itu.int/rec/R-REC-BT.601
+ # # Luminance is in range 0..5000 as each value is 0..5
+ # luminance=$(( (r * 299) + (g * 587) + (b * 114) ))
+ # (( $luminance > 2500 )) && printf "0" || printf "15"
+}
+
+# Print a coloured block with the number of that colour
+function print_colour {
+ local colour="$1" contrast
+ contrast=$(contrast_colour "$1")
+ printf "\e[48;5;%sm" "$colour" # Start block of colour
+ printf "\e[38;5;%sm%3d" "$contrast" "$colour" # In contrast, print number
+ printf "\e[0m " # Reset colour
+}
+
+# Starting at $1, print a run of $2 colours
+function print_run {
+ local i
+ for (( i = "$1"; i < "$1" + "$2" && i < printable_colours; i++ )) do
+ print_colour "$i"
+ done
+ printf " "
+}
+
+# Print blocks of colours
+function print_blocks {
+ local start="$1" i
+ local end="$2" # inclusive
+ local block_cols="$3"
+ local block_rows="$4"
+ local blocks_per_line="$5"
+ local block_length=$((block_cols * block_rows))
+
+ # Print sets of blocks
+ for (( i = start; i <= end; i += (blocks_per_line-1) * block_length )) do
+ printf "\n" # Space before each set of blocks
+ # For each block row
+ for (( row = 0; row < block_rows; row++ )) do
+ # Print block columns for all blocks on the line
+ for (( block = 0; block < blocks_per_line; block++ )) do
+ print_run $(( i + (block * block_length) )) "$block_cols"
+ done
+ (( i += block_cols )) # Prepare to print the next row
+ printf "\n"
+ done
+ done
+}
+
+print_run 0 16 # The first 16 colours are spread over the whole spectrum
+printf "\n"
+print_blocks 16 231 6 6 3 # 6x6x6 colour cube between 16 and 231 inclusive
+print_blocks 232 255 12 2 1 # Not 50, but 24 Shades of Grey
diff --git a/home/.local/bin/scripts/cli/lfu b/home/.local/bin/scripts/cli/lfu
new file mode 100755
index 0000000..224f19b
--- /dev/null
+++ b/home/.local/bin/scripts/cli/lfu
@@ -0,0 +1,24 @@
+#!/bin/sh
+set -e
+
+if [ -n "$DISPLAY" ]; then
+ export FIFO_UEBERZUG="${TMPDIR:-/tmp}/lf-ueberzug-$$"
+
+ cleanup() {
+ exec 3>&-
+ rm "$FIFO_UEBERZUG"
+ }
+
+ mkfifo "$FIFO_UEBERZUG"
+ ueberzug layer -s <"$FIFO_UEBERZUG" &
+ exec 3>"$FIFO_UEBERZUG"
+ trap cleanup EXIT
+
+ if ! [ -d "$HOME/.cache/lf" ]; then
+ mkdir -p "$HOME/.cache/lf"
+ fi
+
+ lf "$@" 3>&-
+else
+ exec lf "$@"
+fi
diff --git a/home/.local/bin/scripts/extra/unix b/home/.local/bin/scripts/extra/unix
new file mode 100755
index 0000000..a9fb96e
--- /dev/null
+++ b/home/.local/bin/scripts/extra/unix
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+#original artwork by http://www.sanderfocus.nl/#/portfolio/tech-heroes
+#converted to shell by #nixers @ irc.unix.chat
+
+cat << 'eof'
+ [38;5;255m,_ ,_==▄▂[0m
+ [38;5;255m, ▂▃▄▄▅▅[48;5;240m▅[48;5;20m▂[48;5;240m▅¾[0m. [38;5;199m/ [38;5;20m/[0m
+ [38;5;255m[48;5;20m▄[0m[38;5;255m[48;5;199m▆[38;5;16m[48;5;255m<´ [38;5;32m"[38;5;34m»[38;5;255m▓▓[48;5;32m▓[48;5;240m%[0m\ [38;5;199m/ [38;5;20m/ [38;5;45m/ [38;5;118m/[0m
+ [38;5;255m,[38;5;255m[48;5;240m▅[38;5;16m[48;5;255m7" [38;5;160m´[38;5;34m>[38;5;255m[48;5;39m▓▓[38;5;199m[48;5;255m▓[0m[38;5;255m% [38;5;20m/ [38;5;118m/ [38;5;199m> [38;5;118m/ [38;5;199m>[38;5;255m/[38;5;45m%[0m
+ [38;5;255m▐[48;5;240m[38;5;255m¶[48;5;240m[38;5;255m▓[48;5;255m [38;5;196m,[38;5;34m»[48;5;201m[38;5;255m▓▓[0m[38;5;255m¾´[0m [38;5;199m/[38;5;255m> %[38;5;199m/[38;5;118m%[38;5;255m/[38;5;199m/ [38;5;45m/ [38;5;199m/[0m
+ [38;5;255m[48;5;240m▓[48;5;255m[38;5;16m▃[48;5;16m[38;5;255m▅▅[38;5;16m[48;5;255m▅▃,,[38;5;32m▄[38;5;16m▅[38;5;255m[48;5;16m▅▅[38;5;255m[48;5;20mÆ[0m[38;5;255m\[0m[38;5;20m/[38;5;118m/[38;5;255m /[38;5;118m/[38;5;199m/[38;5;255m>[38;5;45m// [38;5;255m/[38;5;118m>[38;5;199m/ [38;5;20m/[0m
+ [48;5;20m[38;5;255mV[48;5;255m[38;5;16m║[48;5;20m[38;5;255m«[0m[38;5;255m¼.;[48;5;240m[38;5;255m→[48;5;255m[38;5;16m ║[0m[38;5;255m<«.,[48;5;25m[38;5;255m`[48;5;240m=[0m[38;5;20m/[38;5;199m/ [38;5;255m/>[38;5;45m/[38;5;118m/[38;5;255m%/[38;5;199m% / [38;5;20m/[0m
+ [38;5;20m//[48;5;255m[38;5;16m╠<´ -²,)[48;5;16m[38;5;255m(▓[48;5;255m[38;5;16m~"-[38;5;199m╝/[0m[38;5;255m¾[0m[38;5;199m/ [38;5;118m%[38;5;255m/[38;5;118m>[38;5;45m/ [38;5;118m/[38;5;199m>[0m
+ [38;5;20m/ / [38;5;118m/ [48;5;20m[38;5;255m▐[48;5;240m[38;5;16m%[48;5;255m -./▄▃▄[48;5;16m[38;5;255m▅[48;5;255m[38;5;16m▐[48;5;255m[38;5;16m, [38;5;199m/[48;5;199m[38;5;255m7[0m[38;5;20m/[38;5;199m/[38;5;255m;/[38;5;199m/[38;5;118m% [38;5;20m/ /[0m
+ [38;5;20m/ [38;5;199m/[38;5;255m/[38;5;45m/[38;5;118m/[38;5;255m[48;5;240m`[48;5;20m[38;5;255m▌[48;5;20m[38;5;255m▐[48;5;255m[38;5;16m %z[0m[38;5;255mWv xX[48;5;20m[38;5;255m▓[48;5;34m[38;5;255m▇[48;5;199m[38;255m▌[0m[38;5;20m/[38;5;199m/[38;5;255m&;[38;5;20m% [38;5;199m/ [38;5;20m/[0m
+ [38;5;20m/ / [38;5;255m/ [38;5;118m%[38;5;199m/[38;5;255m/%/[48;5;240m[38;5;255m¾[48;5;255m[38;5;16m½´[38;5;255m[48;5;16m▌[0m[38;5;246m▃▄[38;5;255m▄▄[38;5;246m▄▃▃[0m[48;5;16m[38;5;255m▐[38;5;255m[48;5;199m¶[48;5;20m[38;5;255m\[0m[38;5;20m/[0m[48;5;255m[38;5;240m&[0m [38;5;20m/[0m
+ [38;5;199m<[38;5;118m/ [38;5;45m/[38;5;255m[38;5;118m%[38;5;255m/[38;5;45m/[38;5;255m`[48;5;16m▓[48;5;255m[38;5;16m![48;5;240m[38;5;255m%[48;5;16m[38;5;255m▓[0m[38;5;255m%[48;5;240m[38;5;255m╣[48;5;240m[38;5;255;╣[0m[38;5;255mW[0m[38;5;250mY[38;5;255m)VY>[48;5;240m[38;5;255m7[0m[38;5;255m; [38;5;255m[48;5;240m\[0m[38;5;255m_[0m [38;5;255mUNIX IS VERY SIMPLE [38;5;45mIT JUST NEEDS A[0m
+ [38;5;20m/ [38;5;255m/[38;5;118m<[38;5;255m/ [38;5;45m/[38;5;255m/<[38;5;199m/[38;5;20m/[38;5;199m/[38;5;20m<[38;5;255m_/%\[38;5;255m[48;5;16m▓[48;5;255m[38;5;16m V[0m[38;5;255m%[48;5;255m[38;5;16mW[0m[38;5;255m%£)XY[0m [38;5;240m_/%[38;5;255m‾\_,[0m [38;5;45mGENIUS TO UNDERSTAND ITS SIMPLICITY[38;5;255m[0m
+ [38;5;199m/ [38;5;255m/ [38;5;199m/[38;5;255m/[38;5;118m%[38;5;199m/[48;5;240m[38;5;255m_,=-[48;5;20m-^[0m[38;5;255m/%/%%[48;5;255m[38;5;16m\¾%[0m[38;5;255m¶[0m[48;5;255m[38;5;16m%[0m[38;5;255m%}[0m [38;5;240m/%%%[38;5;20m%%[38;5;240m%;\,[0m
+ [38;5;45m%[38;5;20m/[38;5;199m< [38;5;20m/[48;5;20m[38;5;255m_/[48;5;240m [0m[38;5;255m%%%[38;5;240m%%[38;5;20m;[38;5;255mX[38;5;240m%[38;5;20m%[38;5;255m\%[38;5;240m%;, _/%%%;[38;5;20m,[38;5;240m \[0m
+ [38;5;118m/ [38;5;20m/ [38;5;240m%[38;5;20m%%%%[38;5;240m%;, [38;5;255m\[38;5;240m%[38;5;20m%[38;5;255ml[38;5;240m%%;// _/[38;5;20m%;,[0m [38;5;234mdmr[0m
+ [38;5;20m/ [38;5;240m%[38;5;20m%%;,[0m [38;5;255m<[38;5;20m;[38;5;240m\-=-/ /[0m
+ [38;5;20m;,[0m [38;5;240ml[0m
+eof
diff --git a/home/.local/bin/scripts/gui/brightness b/home/.local/bin/scripts/gui/brightness
new file mode 100755
index 0000000..4efadf0
--- /dev/null
+++ b/home/.local/bin/scripts/gui/brightness
@@ -0,0 +1,153 @@
+#!/bin/sh
+
+
+# Parse arguments
+# ------------------------------------------------------------------------------------
+BRIGHTNESS_DIR="/sys/class/backlight/*"
+SEND_NOTIFICATION=0
+URGENCY="normal"
+INCREASE=0
+DECREASE=0
+SET=0
+BRIGHTNESS=0
+
+while [ "$1" ]; do
+ case "$1" in
+ -h | --help)
+ cat << EOF
+brightness is a cli tool that for displaying or modifying screen brightness.
+
+Options:
+-h | --help: Display this message
+-n | --notification: Produce a desktop notification with brightness info
+-N | --no-notification: Don't produce a desktop notification with brightness info
+-u | --urgency [URGENCY]: Pass over notify-send urgency attribute (default: normal)
+-i | --increase [BRIGHTNESS]: Increase the brightness by given amount
+-d | --decrease [BRIGHTNESS]: Decrease the brightness by given amount
+-s | --set [BRIGHTNESS]: Set new brightness level
+-p | --path [DIR_PATH]: Path to brightness directory (default: /sys/class/backlight/*)
+
+Valid values:
+ URGENCY: low, normal, critical
+ DIR_PATH: Valid path to a directory
+ BRIGHTNESS:
+ specific value - Example: 10
+ percentage value - Example: 10%
+EOF
+ exit 0
+ ;;
+ -n | --notification)
+ SEND_NOTIFICATION=1
+ ;;
+ -N | --no-notification)
+ SEND_NOTIFICATION=0
+ ;;
+ -u | --urgency)
+ URGENCY="$2"
+ shift
+ ;;
+ -i | --increase)
+ INCREASE=1
+ BRIGHTNESS="$2"
+ shift
+ ;;
+ -d | --decrease)
+ DECREASE=1
+ BRIGHTNESS="$2"
+ shift
+ ;;
+ -s | --set)
+ SET=1
+ BRIGHTNESS="$2"
+ shift
+ ;;
+ -p | --path)
+ BRIGHTNESS_DIR="$2"
+ shift
+ ;;
+ * )
+ echo "Unknown argument '$1', use -h or --help for help"
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+# Define constants based on parsed arguments
+# ------------------------------------------------------------------------------------
+BRIGHTNESS_FILE="$BRIGHTNESS_DIR/brightness"
+BRIGHTNESS_MAX="$(cat $BRIGHTNESS_DIR/max_brightness)"
+
+
+# Helper functins
+# ------------------------------------------------------------------------------------
+
+# Send brightness level desktop notification, showing the given brightness level
+# as progress bar, along with given message.
+# $1 - brightness level (number 0-100)
+# $2 - message (notification body)
+send_brightness_notify() {
+ percent_brightness="$1"
+ msg="$2"
+
+ notify-send \
+ --app-name=brightness \
+ --urgency="$URGENCY" \
+ -h int:value:$percent_brightness \
+ -h string:synchronous:brightness \
+ "brightness" "$msg"
+}
+
+
+# Set brightness to given absolute value
+# $1 - brightness absolute value
+set_brightness() {
+ # there should be sudo config allowing this command without password
+ echo "$1" | sudo tee $BRIGHTNESS_FILE >/dev/null
+}
+
+
+# Main Logic
+# ------------------------------------------------------------------------------------
+
+# Determine the absolute new brightness level
+if [ $INCREASE -eq 1 ] || [ $DECREASE -eq 1 ] || [ $SET -eq 1 ]; then
+ # If we're dealing with percentages, change to absolutes
+ if echo "$BRIGHTNESS" | grep -qE '%$'; then
+ numeric=$(echo "$BRIGHTNESS" | sed 's/.$//')
+ absolute=$(echo "($BRIGHTNESS_MAX / 100) * $numeric" | bc -l)
+ BRIGHTNESS=$(printf "%.0f" $absolute)
+ fi
+
+ # Get the new requested absolute brightness
+ if [ $SET -eq 1 ]; then
+ new_brightness=$BRIGHTNESS
+ elif [ $DECREASE -eq 1 ]; then
+ cur_brightness=$(cat $BRIGHTNESS_FILE)
+ new_brightness=$(($cur_brightness - $BRIGHTNESS))
+ else
+ cur_brightness=$(cat $BRIGHTNESS_FILE)
+ new_brightness=$(($cur_brightness + $BRIGHTNESS))
+ fi
+
+ # Ensure we respect max/min boundaries
+ if [ $new_brightness -lt 0 ]; then
+ new_brightness=0
+ elif [ $new_brightness -gt $BRIGHTNESS_MAX ]; then
+ new_brightness=$BRIGHTNESS_MAX
+ fi
+
+ # Update the brightness
+ set_brightness $new_brightness
+fi
+
+cur_brightness=$(cat $BRIGHTNESS_FILE)
+percent_brightness=$(echo "($cur_brightness / $BRIGHTNESS_MAX) * 100" | bc -l)
+percent_brightness_2f=$(printf "%.2f" $percent_brightness)
+percent_brightness_rounded=$(printf "%.0f" $percent_brightness)
+
+if [ $SEND_NOTIFICATION -eq 1 ]; then
+ send_brightness_notify "$percent_brightness_rounded" "Level: $percent_brightness_rounded"
+fi
+
+echo "Brightness: ${percent_brightness_2f}% (absolute: $cur_brightness)"
diff --git a/home/.local/bin/scripts/gui/deskopen b/home/.local/bin/scripts/gui/deskopen
new file mode 100755
index 0000000..98d8280
--- /dev/null
+++ b/home/.local/bin/scripts/gui/deskopen
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Find the line with exec, if there's multiple lines
+# use the last one
+exec_line=$(grep '^Exec' "$1" | tail -1)
+# Remove 'Exec' and arguments (%u, %f, ...)
+cmd=$(echo $exec_line | sed 's/^Exec=//' | sed 's/%.//')
+# Remove "" around command (if present)
+cmd=$(echo $cmd | sed 's/^"//g' | sed 's/" *$//g')
+# Run the exec line of the application using /bin/sh
+/bin/sh -c "$cmd"
diff --git a/home/.local/bin/scripts/gui/dmenu b/home/.local/bin/scripts/gui/dmenu
new file mode 100755
index 0000000..f58a2e5
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# Compatibility executable script for applications running dmenu, which
+# runs wofi in dmenu mode instead. Note: In many cases the arguments won't
+# be compatible and this will fail, however the primary way scripts use
+# dmenu is just for simple prompts, using the `-p` flag. and wofi does fully
+# support this usage.
+
+cat | wofi --dmenu $@
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/displayselect b/home/.local/bin/scripts/gui/dmenu-scripts/displayselect
new file mode 100755
index 0000000..8d7997c
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/displayselect
@@ -0,0 +1,85 @@
+
+#!/bin/sh
+
+# A UI for detecting and selecting all displays. Probes xrandr for connected
+# displays and lets user select one to use. User may also select "manual
+# selection" which opens arandr.
+
+twoscreen() { # If multi-monitor is selected and there are two screens.
+
+ mirror=$(printf "no\\nyes" | dmenu -i -p "Mirror displays?")
+ # Mirror displays using native resolution of external display and a scaled
+ # version for the internal display
+ if [ "$mirror" = "yes" ]; then
+ external=$(echo "$screens" | dmenu -i -p "Optimize resolution for:")
+ internal=$(echo "$screens" | grep -v "$external")
+
+ res_external=$(xrandr --query | sed -n "/^$external/,/\+/p" | \
+ tail -n 1 | awk '{print $1}')
+ res_internal=$(xrandr --query | sed -n "/^$internal/,/\+/p" | \
+ tail -n 1 | awk '{print $1}')
+
+ res_ext_x=$(echo "$res_external" | sed 's/x.*//')
+ res_ext_y=$(echo "$res_external" | sed 's/.*x//')
+ res_int_x=$(echo "$res_internal" | sed 's/x.*//')
+ res_int_y=$(echo "$res_internal" | sed 's/.*x//')
+
+ scale_x=$(echo "$res_ext_x / $res_int_x" | bc -l)
+ scale_y=$(echo "$res_ext_y / $res_int_y" | bc -l)
+
+ xrandr --output "$external" --auto --scale 1.0x1.0 \
+ --output "$internal" --auto --same-as "$external" \
+ --scale "$scale_x"x"$scale_y"
+ else
+
+ primary=$(echo "$screens" | dmenu -i -p "Select primary display:")
+ secondary=$(echo "$screens" | grep -v "$primary")
+ direction=$(printf "left\\nright" | dmenu -i -p "What side of $primary should $secondary be on?")
+ xrandr --output "$primary" --auto --scale 1.0x1.0 --output "$secondary" --"$direction"-of "$primary" --auto --scale 1.0x1.0
+ fi
+ }
+
+morescreen() { # If multi-monitor is selected and there are more than two screens.
+ primary=$(echo "$screens" | dmenu -i -p "Select primary display:")
+ secondary=$(echo "$screens" | grep -v "$primary" | dmenu -i -p "Select secondary display:")
+ direction=$(printf "left\\nright" | dmenu -i -p "What side of $primary should $secondary be on?")
+ tertiary=$(echo "$screens" | grep -v "$primary" | grep -v "$secondary" | dmenu -i -p "Select third display:")
+ xrandr --output "$primary" --auto --output "$secondary" --"$direction"-of "$primary" --auto --output "$tertiary" --"$(printf "left\\nright" | grep -v "$direction")"-of "$primary" --auto
+ }
+
+multimon() { # Multi-monitor handler.
+ case "$(echo "$screens" | wc -l)" in
+ 2) twoscreen ;;
+ *) morescreen ;;
+ esac ;}
+
+onescreen() { # If only one output available or chosen.
+ xrandr --output "$1" --auto --scale 1.0x1.0 $(echo "$allposs" | grep -v "\b$1" | awk '{print "--output", $1, "--off"}' | paste -sd ' ' -)
+ }
+
+postrun() { # Stuff to run to clean up.
+ command -v setbg >/dev/null && setbg # Fix background if screen size/arangement has changed.
+ }
+
+# Get all possible displays
+allposs=$(xrandr -q | grep "connected")
+
+# Get all connected screens.
+screens=$(echo "$allposs" | awk '/ connected/ {print $1}')
+
+# If there's only one screen
+if [ "$(echo "$screens" | wc -l)" -lt 2 ]; then
+ onescreen "$screens"
+ notify-send "💻 Only one screen detected." "Using it in its optimal settings..."
+else
+ # Get user choice including multi-monitor and manual selection:
+ chosen=$(printf "%s\\nmulti-monitor\\nmanual selection" "$screens" | dmenu -i -p "Select display arangement:") &&
+ case "$chosen" in
+ "manual selection") arandr ; exit ;;
+ "multi-monitor") multimon ;;
+ *) onescreen "$chosen" ;;
+ esac
+fi
+
+
+postrun
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/dman b/home/.local/bin/scripts/gui/dmenu-scripts/dman
new file mode 100755
index 0000000..fdcb93e
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/dman
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# Dmenu prompt to easily search for a man page to open
+
+page="$(apropos --long "$1" | dmenu -i -l 10 | awk '{print $2, $1}' | tr -d '()')"
+
+if tty -s; then
+ man $page
+else
+ $TERMINAL -e man $page
+fi
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/dmenumount b/home/.local/bin/scripts/gui/dmenu-scripts/dmenumount
new file mode 100755
index 0000000..2793633
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/dmenumount
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+# Gives dmenu prompt to mount unmounted drives and Android phones.
+# If they're in /etc/fstab they'll be mounted automatically.
+# Otherwise, you'll be prompted to give a mountpoint from already
+# existing directories. If you input a novel directory, it will
+# prompt you to create that directory.
+
+getmount() { \
+ [ -z "$chosen" ] && exit 1
+ # shellcheck disable=SC2086
+ mp="$(find $1 2>/dev/null | dmenu -i -p "Type in mount point.")" || exit 1
+ test -z "$mp" && exit 1
+ if [ ! -d "$mp" ]; then
+ mkdiryn=$(printf "No\\nYes" | dmenu -i -p "$mp does not exist. Create it?") || exit 1
+ [ "$mkdiryn" = "Yes" ] && (mkdir -p "$mp" || sudo -A mkdir -p "$mp")
+ fi
+ }
+
+mountusb() { \
+ chosen="$(echo "$usbdrives" | dmenu -i -p "Mount which drive?")" || exit 1
+ chosen="$(echo "$chosen" | awk '{print $1}')"
+ sudo -A mount "$chosen" 2>/dev/null && notify-send "💻 USB mounting" "$chosen mounted." && exit 0
+ alreadymounted=$(lsblk -nrpo "name,type,mountpoint" | awk '$3!~/\/boot|\/home$|SWAP/&&length($3)>1{printf "-not ( -path *%s -prune ) ",$3}')
+ getmount "/mnt /media /mount /home -maxdepth 5 -type d $alreadymounted"
+ partitiontype="$(lsblk -no "fstype" "$chosen")"
+ case "$partitiontype" in
+ "vfat") sudo -A mount -t vfat "$chosen" "$mp" -o rw,umask=0000;;
+ "exfat") sudo -A mount "$chosen" "$mp" -o uid="$(id -u)",gid="$(id -g)";;
+ *) sudo -A mount "$chosen" "$mp"; user="$(whoami)"; ug="$(groups | awk '{print $1}')"; sudo -A chown "$user":"$ug" "$mp";;
+ esac
+ notify-send "💻 USB mounting" "$chosen mounted to $mp."
+ }
+
+mountandroid() { \
+ chosen="$(echo "$anddrives" | dmenu -i -p "Which Android device?")" || exit 1
+ chosen="$(echo "$chosen" | cut -d : -f 1)"
+ getmount "$HOME -maxdepth 3 -type d"
+ simple-mtpfs --device "$chosen" "$mp"
+ echo "OK" | dmenu -i -p "Tap Allow on your phone if it asks for permission and then press enter" || exit 1
+ simple-mtpfs --device "$chosen" "$mp"
+ notify-send "🤖 Android Mounting" "Android device mounted to $mp."
+ }
+
+asktype() { \
+ choice="$(printf "USB\\nAndroid" | dmenu -i -p "Mount a USB drive or Android device?")" || exit 1
+ case $choice in
+ USB) mountusb ;;
+ Android) mountandroid ;;
+ esac
+ }
+
+anddrives=$(simple-mtpfs -l 2>/dev/null)
+usbdrives="$(lsblk -rpo "name,type,size,mountpoint" | grep 'part\|rom' | awk '$4==""{printf "%s (%s)\n",$1,$3}')"
+
+if [ -z "$usbdrives" ]; then
+ [ -z "$anddrives" ] && echo "No USB drive or Android device detected" && exit
+ echo "Android device(s) detected."
+ mountandroid
+else
+ if [ -z "$anddrives" ]; then
+ echo "USB drive(s) detected."
+ mountusb
+ else
+ echo "Mountable USB drive(s) and Android device(s) detected."
+ asktype
+ fi
+fi
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/dmenupass b/home/.local/bin/scripts/gui/dmenu-scripts/dmenupass
new file mode 100755
index 0000000..8d5ce30
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/dmenupass
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# This script is the value for SUDO_ASKPASS variable,
+# meaning that it will be used as a password prompt if needed.
+
+dmenu -P -p "$1"
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/dmenuprompt b/home/.local/bin/scripts/gui/dmenu-scripts/dmenuprompt
new file mode 100755
index 0000000..4d0adec
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/dmenuprompt
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Opens a basic yes/no prompt with dmenu
+# This is useful for confirming whether an action should be taken
+
+# First try to run with restrict (-r) flag
+# however not everyone has this patch applied, so if that fails, fall back
+out="$(printf "No\nYes" | dmenu -i -r -p "$1" 2>/dev/null)"
+if [ $? -ne 0 ]; then
+ out="$(printf "No\nYes" | dmenu -i -p "$1")"
+fi
+
+
+if [ "$out" == "Yes" ]; then
+ exit 0
+elif [ "$out" == "No" ]; then
+ exit 1
+else
+ # Dmenu allows invalid picks by explicitly typing in a different option
+ # when that happens, end with code 2 instead.
+ exit 2
+fi
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/dmenurecord b/home/.local/bin/scripts/gui/dmenu-scripts/dmenurecord
new file mode 100755
index 0000000..60ce8dc
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/dmenurecord
@@ -0,0 +1,121 @@
+
+#!/bin/sh
+
+# Usage:
+# `$0`: Ask for recording type via dmenu
+# `$0 screencast`: Record both audio and screen
+# `$0 video`: Record only screen
+# `$0 audio`: Record only audio
+# `$0 kill`: Kill existing recording
+#
+# If there is already a running instance, user will be prompted to end it.
+
+screencast() {
+ ffmpeg -y \
+ -f x11grab \
+ -framerate 60 \
+ -s "$(xdpyinfo | grep dimensions | awk '{print $2;}')" \
+ -i "$DISPLAY" \
+ -f alsa -i default \
+ -r 30 \
+ -c:v h264 -crf 0 -preset ultrafast -c:a aac \
+ "$HOME/screencast-$(date '+%y%m%d-%H%M-%S').mp4" &
+ echo $! > /tmp/recordingpid
+}
+
+video() {
+ ffmpeg \
+ -f x11grab \
+ -s "$(xdpyinfo | grep dimensions | awk '{print $2;}')" \
+ -i "$DISPLAY" \
+ -c:v libx264 -qp 0 -r 30 \
+ "$HOME/video-$(date '+%y%m%d-%H%M-%S').mkv" &
+ echo $! > /tmp/recordingpid
+}
+
+webcamhidef() {
+ ffmpeg \
+ -f v4l2 \
+ -i /dev/video0 \
+ -video_size 1920x1080 \
+ "$HOME/webcam-$(date '+%y%m%d-%H%M-%S').mkv" &
+ echo $! > /tmp/recordingpid
+}
+
+webcam() {
+ ffmpeg \
+ -f v4l2 \
+ -i /dev/video0 \
+ -video_size 640x480 \
+ "$HOME/webcam-$(date '+%y%m%d-%H%M-%S').mkv" &
+ echo $! > /tmp/recordingpid
+}
+
+
+audio() {
+ ffmpeg \
+ -f alsa -i default \
+ "$HOME/audio-$(date '+%y%m%d-%H%M-%S').mp3" &
+ echo $! > /tmp/recordingpid
+}
+
+asktoend() {
+ response=$(printf "No\\nYes" | dmenu -i -p "Recording still active. End recording?") &&
+ [ "$response" = "Yes" ] && killrecording
+}
+
+videoselected()
+{
+ slop -f "%x %y %w %h" > /tmp/slop
+ read -r X Y W H < /tmp/slop
+ rm /tmp/slop
+
+ ffmpeg \
+ -f x11grab \
+ -framerate 60 \
+ -video_size "$W"x"$H" \
+ -i :0.0+"$X,$Y" \
+ -c:v libx264 -qp 0 -r 30 \
+ "$HOME/box-$(date '+%y%m%d-%H%M-%S').mkv" &
+ echo $! > /tmp/recordingpid
+}
+
+killrecording() {
+ recpid="$(cat /tmp/recordingpid)"
+ # kill with SIGTERM, allowing finishing touches.
+ kill -15 "$recpid" 2>/dev/null
+ rm -f /tmp/recordingpid
+ # even after SIGTERM, ffmpeg may still run, so SIGKILL it.
+ sleep 3
+ kill -9 "$recpid" 2>/dev/null
+ exit
+}
+
+askrecording() { \
+ choice=$(printf "screencast\\nvideo\\nvideo selected\\naudio\\nwebcam\\nwebcam (hi-def)" | dmenu -i -p "Select recording style:")
+ case "$choice" in
+ screencast) screencast;;
+ audio) audio;;
+ video) video;;
+ *selected) videoselected;;
+ webcam) webcam;;
+ "webcam (hi-def)") webcamhidef;;
+ esac
+}
+
+case "$1" in
+ screencast) screencast;;
+ audio) audio;;
+ video) video;;
+ *selected) videoselected;;
+ kill) killrecording;;
+ *)
+ if [ -f /tmp/recordingpid ]; then
+ recpid="$(cat /tmp/recordingpid)"
+ if ps -p $recpid > /dev/null; then
+ asktoend
+ exit
+ fi
+ fi
+ askrecording;;
+esac
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/dmenuumount b/home/.local/bin/scripts/gui/dmenu-scripts/dmenuumount
new file mode 100755
index 0000000..26612ef
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/dmenuumount
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# A dmenu prompt to unmount drives.
+# Provides you with mounted partitions, select one to unmount.
+# Drives mounted at /, /boot and /home will not be options to unmount.
+
+unmountusb() {
+ [ -z "$drives" ] && exit
+ chosen="$(echo "$drives" | dmenu -i -p "Unmount which drive?")" || exit 1
+ chosen="$(echo "$chosen" | awk '{print $1}')"
+ [ -z "$chosen" ] && exit
+ sudo -A umount "$chosen" && notify-send "💻 USB unmounting" "$chosen unmounted."
+ }
+
+unmountandroid() { \
+ chosen="$(awk '/simple-mtpfs/ {print $2}' /etc/mtab | dmenu -i -p "Unmount which device?")" || exit 1
+ [ -z "$chosen" ] && exit
+ sudo -A umount -l "$chosen" && notify-send "🤖 Android unmounting" "$chosen unmounted."
+ }
+
+asktype() { \
+ choice="$(printf "USB\\nAndroid" | dmenu -i -p "Unmount a USB drive or Android device?")" || exit 1
+ case "$choice" in
+ USB) unmountusb ;;
+ Android) unmountandroid ;;
+ esac
+ }
+
+drives=$(lsblk -nrpo "name,type,size,mountpoint" | awk '$4!~/\/boot|\/home$|SWAP/&&length($4)>1{printf "%s (%s)\n",$4,$3}')
+
+if ! grep simple-mtpfs /etc/mtab; then
+ [ -z "$drives" ] && echo "No drives to unmount." && exit
+ echo "Unmountable USB drive detected."
+ unmountusb
+else
+ if [ -z "$drives" ]
+ then
+ echo "Unmountable Android device detected."
+ unmountandroid
+ else
+ echo "Unmountable USB drive(s) and Android device(s) detected."
+ asktype
+ fi
+fi
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/pyrun b/home/.local/bin/scripts/gui/dmenu-scripts/pyrun
new file mode 100755
index 0000000..aced1a5
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/pyrun
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# Simple wrapper to quickly execute a simple python command and have it printed out.
+# The output is then sent back via notification.
+#
+# This already has random imported, since that's a common use-case for this script.
+
+echo "" | dmenu -i -p "Python" | xargs -0 -I % python -c "import random;print(%)" | xargs -I % notify-send "Pyrun output:" "%"
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/todo b/home/.local/bin/scripts/gui/dmenu-scripts/todo
new file mode 100755
index 0000000..4cf8c90
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/todo
@@ -0,0 +1,36 @@
+#!/bin/sh
+# This is inspired by dmenu's todo script made by suckless
+#
+# Manage TODO tasks in dmenu by writing them, remove by selecting
+# an existing entry
+#
+# Configurable variables
+# ---------------------------------------------------------------------
+
+FILE="${XDG_DATA_HOME:-$HOME/.local/share}/todos"
+PROMPT="Add/delete a task: "
+
+# Logic
+# ---------------------------------------------------------------------
+mkdir -p "$(dirname $FILE)"
+touch "$FILE"
+
+height=$(wc -l "$FILE" | awk '{print $1}')
+
+# Run dmenu and keep restarting it until it returns an empty output
+cmd=$(dmenu -l "$height" -p "$PROMPT" "$@" < "$FILE")
+while [ -n "$cmd" ]; do
+ # If the output matched an existing TODO, remove it
+ if grep -q "^$cmd\$" "$FILE"; then
+ grep -v "^$cmd\$" "$FILE" > "$FILE.$$"
+ mv "$FILE.$$" "$FILE"
+ height=$(( height - 1 ))
+ # If the output didn't match an existing TODO, it's a new one, add it
+ else
+ echo "$cmd" >> "$FILE"
+ height=$(( height + 1 ))
+ fi
+
+ # Keep restarting until empty output
+ cmd=$(dmenu -l "$height" -p "$PROMPT" "$@" < "$FILE")
+done
diff --git a/home/.local/bin/scripts/gui/dmenu-scripts/website-link b/home/.local/bin/scripts/gui/dmenu-scripts/website-link
new file mode 100755
index 0000000..c7a525f
--- /dev/null
+++ b/home/.local/bin/scripts/gui/dmenu-scripts/website-link
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+import feedparser
+import subprocess
+
+
+URL = "https://itsdrike.com/posts/index.xml"
+
+
+def main():
+ feed = feedparser.parse(URL)
+ titles = {entry['title']: entry['link'] for entry in feed['entries']}
+
+ selected_page = subprocess.check_output(
+ ["dmenu", "-i", "-p", "Post"],
+ input="\n".join(titles.keys()), universal_newlines=True
+ )
+ link = titles[selected_page.strip()]
+
+ subprocess.check_output(["xsel", "-bi"], input=link, universal_newlines=True)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/home/.local/bin/scripts/gui/gh-notification b/home/.local/bin/scripts/gui/gh-notification
new file mode 100755
index 0000000..42be614
--- /dev/null
+++ b/home/.local/bin/scripts/gui/gh-notification
@@ -0,0 +1,299 @@
+#!/bin/sh
+
+# Parse arguments
+# ------------------------------------------------------------------------------------
+ALL=0
+VERBOSE=0
+VERY_VERBOSE=0
+VERY_VERY_VERBOSE=0
+TEMP_SHOW=0
+DRY_RUN=0
+NO_CACHE=0
+NO_DISPLAY=0
+URGENCY="normal"
+RESET=0
+while [ "$1" ]; do
+ case "$1" in
+ -h | --help)
+ cat << EOF
+gh-notification is a tool that scrapes unread github notifications
+It uses github-cli with meiji163/gh-notify addon to obtain the unread notifications
+these are then parsed and sent as desktop notifications with notify-send
+
+Options:
+-a | --all: Also process already read notifications
+-t | --temp-files: Show names of used temporary files for each notification
+-v | --verbose: Shows info about what's happening.
+-vv | --very-verbose: Implies --verbose, shows some more info about what's happening
+-vvv | --very-very-verbose: Implies --very-verbose and --temp-files, shows even more details, usually just for debugging
+-d | --dry-run: Run without sending any notificatinos, when ran with -r, this will also prevent any actual cache file removals
+-nc | --no-cache: Ignore the cache and send all found notifications, even if they were already sent before.
+-nd | --no-display: When the script is ran from headless mode (such as by crontab), this will still attempt to set the DISPLAY and send the desktop notification
+-r | --reset: Resets notification cache (storing which notifications were already sent), skips notification sending, WARNING: removes the whole cache, regardless of '--all')
+-u | --urgency [urgency-level]: pass over notify-send urgency attribute (low, normal, critical)
+EOF
+ exit 0
+ ;;
+ -a | --all)
+ ALL=1
+ ;;
+ -t | --temp-files)
+ TEMP_SHOW=1
+ ;;
+ -v | --verbose)
+ VERBOSE=1
+ ;;
+ -vv | --very-verbose)
+ VERBOSE=1
+ VERY_VERBOSE=1
+ ;;
+ -vvv | --very-very-verbose)
+ VERBOSE=1
+ TEMP_SHOW=1
+ VERY_VERBOSE=1
+ VERY_VERY_VERBOSE=1
+ ;;
+ -d | --dry-run)
+ DRY_RUN=1
+ ;;
+ -nc | --no-cache)
+ NO_CACHE=1
+ ;;
+ -nd | --no-display)
+ NO_DISPLAY=1
+ ;;
+ -u | --urgency)
+ URGENCY="$2"
+ shift
+ ;;
+ -r | --reset)
+ RESET=1
+ ;;
+ * )
+ echo "Unknown argument '$1', use -h or --help for help"
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+
+# Perform cache resetting, if requested
+# ------------------------------------------------------------------------------------
+if [ $RESET -eq 1 ]; then
+ if [ $NO_CACHE -eq 1 ]; then
+ echo "Can't ignore cache when resetting the cache..."
+ exit 1
+ fi
+ out="$(find /tmp -maxdepth 1 -name 'gh-notification-*' 2>/dev/null)"
+ total="$(printf "%s\n" "$out" | wc -l)"
+ # Since we always end with a newline (to count the last entry as a line), we always get
+ # at least 1 as a total here, even if $out is empty. If we didn't use the \n, we'd always
+ # get 0, even if there was a single line, since it wasn't ended with a newline. To figure
+ # out whether there really is a line or not when we get a total of 1, we run character
+ # amount check as well
+ [ "$total" -eq 1 ] && [ "$(printf "%s" "$out" | wc -c)" -eq 0 ] && total=0
+
+ if [ $total -gt 0 ]; then
+ # Since the loop is running in a pipe, it can't modify variables, but we need to know
+ # which files have failed to be removed, so to get that information, we store it in a
+ # teporary file
+ fail_files_file="$(mktemp)"
+
+ printf "%s\n" "$out" | while read -r file_name; do
+ # If desired, let user know about the found notification cache file
+ if [ $VERY_VERBOSE -eq 1 ] || [ $TEMP_SHOW -eq 1 ]; then
+ contents="$(cat "$file_name")"
+ title="$(printf "%s" "$contents" | awk -F '~@~' '{ print $1 }')"
+
+ echo "Found cache tempfile: '$file_name' - $title"
+ if [ $VERY_VERY_VERBOSE -eq 1 ]; then
+ description="$(printf "%s" "$contents" | awk -F '~@~' '{ print $2 }')"
+ echo "Notification description: $description"
+ fi
+ fi
+
+ if [ $DRY_RUN -ne 1 ]; then
+ # In case `rm` fails, keep track of which files it failed on
+ if ! rm "$file_name" 2>/dev/null; then
+ printf "%s\n" "$file_name" >> "$fail_files_file"
+ fi
+ else
+ [ $VERY_VERY_VERBOSE -eq 1 ] && echo "Tempfile removal skipped (dry-run)"
+ fi
+
+ # Add a new-line separator on very very verbose to group prints from each iteration
+ [ $VERY_VERY_VERBOSE -eq 1 ] && echo ""
+ done
+
+ # Recover failed files from the temporary file
+ failed_files="$(cat "$fail_files_file")"
+ failed="$(printf "%s" "$fail_files_file" | wc -l)"
+ rm "$fail_files_file"
+
+ if [ $VERBOSE -eq 1 ]; then
+ echo "Notification cache was reset."
+ removed_count="$(("$total"-"$failed"))"
+ if [ $DRY_RUN -eq 1 ]; then
+ echo "Removed $removed_count files (dry-run: no files were actually removed)"
+ else
+ echo "Removed $removed_count files"
+ fi
+ fi
+
+ # If some cache files were'nt removed successfully, inform the user about it
+ # regardless of verbosity, this shouldn't go silent, even though it may be fine
+ if [ "$failed" -gt 0 ]; then
+ echo "WARNING: Failed to remove $failed files."
+ echo "You probably don't have permission to remove these."
+ echo "Perhaps these were made by someone else? If so, you can ignore this warning."
+ if [ $VERBOSE -eq 0 ]; then
+ echo "Run with --verbose to show exactly which files weren't removed."
+ else
+ echo "These are:"
+ echo "$failed_files"
+ fi
+ fi
+ else
+ [ $VERBOSE -eq 1 ] && echo "No cache files found, nothing to reset"
+ fi
+ exit 0
+fi
+
+
+# Helper functins
+# ------------------------------------------------------------------------------------
+# This runs notify-send, and if NO_DISPLAY is set and we're running in headless
+# mode, this will still try to send the notification by manually setting DISPLAY
+# This also has a special handle that checks if dunst is the notification daemon
+# in which case instead of using notify-send, we use dunstify to send the
+# notification, with which we can also specify some more values.
+send_notify() {
+ if [ $NO_DISPLAY -eq 1 ]; then
+ XDG_RUNTIME_DIR="/run/user/$(id -u)" \
+ DISPLAY=:0 \
+ notify-send --app-name=github-notification --urgency="$URGENCY" "$1" "$2"
+ else
+ notify-send --app-name=github-notification --urgency="$URGENCY" "$1" "$2"
+ fi
+}
+
+
+# Obtain notifications and show them, if they weren't showed (aren't in cache) already
+# ------------------------------------------------------------------------------------
+# Request unread notifications with gh-notify extension for github-cli
+[ "$ALL" -eq 1 ] && out="$(gh notify -s -a)" || out="$(gh notify -s)"
+total="$(printf "%s\n" "$out" | wc -l)"
+# Since we always end with a newline (to count the last entry as a line), we always get
+# at least 1 as a total here, even if $out is empty. If we didn't use the \n, we'd always
+# get 0, even if there was a single line, since it wasn't ended with a newline. To figure
+# out whether there really is a line or not when we get a total of 1, we run character
+# amount check as well
+[ "$total" -eq 1 ] && [ "$(printf "%s" "$out" | wc -c)" -eq 0 ] && total=0
+
+# Only run if we actually found some notifications
+if [ "$total" -gt 0 ]; then
+ # Since the loop is running in a pipe, it can't modify variables, but we need to know
+ # how many notifications were sent, so to ge that information, we store it in a
+ # temporary file
+ sent_count_file="$(mktemp)"
+ printf "0" > "$sent_count_file"
+
+ # Go through each notification, one by one
+ printf "%s\n" "$out" | while read -r line; do
+ # Parse out the data from given output lines
+ issue_type="$(echo "$line" | awk '{print $4}' | sed 's/\x1b\[[0-9;]*m//g')"
+ repo_id="$(echo "$line" | awk '{print $3}' | sed 's/\x1b\[[0-9;]*m//g')"
+
+
+ if [ "$issue_type" == "PullRequest" ]; then
+ issue_id="$(echo "$line" | awk '{print $5}' | sed 's/\x1b\[[0-9;]*m//g' | cut -c2-)"
+ description="$(echo "$line" | awk '{for (i=6; i "$temp_file"
+ hashsum="$(sum < "$temp_file" | cut -f 1 -d ' ')"
+ rm "$temp_file"
+
+ tmpname="/tmp/gh-notification-$hashsum"
+ [ $TEMP_SHOW -eq 1 ] && echo "Tempfile: $tmpname"
+
+ # If the temporary file is already present, this notification was already
+ # send and we don't want to re-send it
+
+ # Only sent the notification if it wasn't already cached (doesn't have temp file)
+ # this avoids resending the same notifications
+ if [ ! -e "$tmpname" ] || [ $NO_CACHE -eq 1 ]; then
+ if [ $DRY_RUN -eq 1 ]; then
+ [ $VERY_VERBOSE -eq 1 ] && echo "Sending notification (dry-run, no actual notification was sent)"
+ else
+ [ $VERY_VERBOSE -eq 1 ] && echo "Sending notification"
+ send_notify "$name" "$description <$url>"
+ # Create the tempfile so that in the next run, we won't resend this notification again
+ # NOTE: We're storing the name and description into this file to make it easier
+ # to figure out what notification the tempfile belongs to, with ~@~ separator
+ printf "%s~@~%s" "$name" "$description" > "$tmpname"
+ fi
+ # Keep track of how many notifications were sent (didn't have a cache file)
+ sent="$(cat "$sent_count_file")"
+ sent="$(("$sent"+1))"
+ printf "%s" "$sent" > "$sent_count_file"
+ else
+ [ $VERY_VERBOSE -eq 1 ] && echo "Skipping (cached) - notification already sent"
+ fi
+
+ # Add a new-line separator on very verbose to group prints from each iteration
+ [ $VERY_VERBOSE -eq 1 ] && echo ""
+ done
+
+ # Recover amount of sent notifications from the temporary file
+ sent="$(cat "$sent_count_file")"
+ rm "$sent_count_file"
+
+ if [ $VERBOSE -eq 1 ]; then
+ unsent="$(("$total"-"$sent"))"
+ if [ "$sent" -eq "$total" ]; then
+ echo "Found and sent $total new notifications"
+ elif [ "$unsent" -eq "$total" ]; then
+ echo "Found $total notifications, all of which were already sent (no new notifications to send)"
+ else
+ echo "Found $total notifications, of which $sent were new and sent ($unsent were skipped - cached/already sent)"
+ fi
+ fi
+else
+ [ $VERBOSE -eq 1 ] && echo "No new notifications"
+fi
diff --git a/home/.local/bin/scripts/gui/setbg b/home/.local/bin/scripts/gui/setbg
new file mode 100755
index 0000000..d1ce331
--- /dev/null
+++ b/home/.local/bin/scripts/gui/setbg
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# This script does the following:
+# Run by itself, set the wallpaper
+# If given a file, set that as the new wallpaper
+# If given a directory, recursively choose a random file in it.
+
+# Location of the symlink to wallpaper image
+bgloc="${XDG_DATA_HOME:-$HOME/.local/share}/background"
+
+trueloc="$(readlink -f "$1")" &&
+case "$(file --mime-type -b "$trueloc")" in
+ image/* )
+ ln -sf "$(readlink -f "$1")" "$bgloc"
+ notify-send -i "$bgloc" "Changing wallpaper..."
+ ;;
+ inode/directory )
+ randimg="$(find -L $trueloc -iregex '.*.\(jpg\|jpeg\|png\|gif\)' -type f | shuf -n 1)"
+ echo $randimg
+ ln -sf "$randimg" "$bgloc"
+ notify-send -i "$bgloc" "Random Wallpaper chosen."
+ ;;
+ *)
+ notify-send "Error" "Not a valid image."
+ exit 1
+ ;;
+esac
+
+# Use xwallpaper to set the background
+if [ "$XDG_SESSION_TYPE" == "wayland" ]; then
+ killall swaybg 2>/dev/null
+ swaybg --image "$bgloc" & disown
+else
+ xwallpaper --zoom "$bgloc"
+fi
diff --git a/home/.mozilla b/home/.mozilla
new file mode 120000
index 0000000..2cf2199
--- /dev/null
+++ b/home/.mozilla
@@ -0,0 +1 @@
+.config/mozilla
\ No newline at end of file
diff --git a/home/.pki b/home/.pki
new file mode 120000
index 0000000..2aacf8b
--- /dev/null
+++ b/home/.pki
@@ -0,0 +1 @@
+.config/pki
\ No newline at end of file
diff --git a/home/.python_history b/home/.python_history
new file mode 120000
index 0000000..e43cfa6
--- /dev/null
+++ b/home/.python_history
@@ -0,0 +1 @@
+.cache/python_history
\ No newline at end of file
diff --git a/root/.rsync-filter b/root/.rsync-filter
new file mode 100644
index 0000000..a19ad20
--- /dev/null
+++ b/root/.rsync-filter
@@ -0,0 +1,22 @@
+# Filter file for rsync based backups
+# rsync needs to be ran with --filter 'dir-merge /.rsync-filter'
+# argument to look through this filter file
+- /dev/*
+- /proc/*
+- /sys/*
+- /media/*
+- /mnt/*
+- /tmp/*
+- /run/*
+- /var/run/*
+- /var/lock/*
+- /var/lib/docker/*
+- /var/lib/schroot/*
+- /lost+found
+- /data/*
+- /DATA/*
+- /cdrom/*
+- /sdcard/*
+- /swapfile
+- /swap/*
+- /home/*/.cache/*
diff --git a/root/etc/crypttab b/root/etc/crypttab
new file mode 100644
index 0000000..d0f0493
--- /dev/null
+++ b/root/etc/crypttab
@@ -0,0 +1,13 @@
+# Configuration for encrypted block devices.
+# See crypttab(5) for details.
+
+# NOTE: Do not list your root (/) partition here, it must be set up
+# beforehand by the initramfs (/etc/mkinitcpio.conf).
+
+#
+# home UUID=b8ad5c18-f445-495d-9095-c9ec4f9d2f37 /etc/mypassword1
+# data1 /dev/sda3 /etc/mypassword2
+# data2 /dev/sda5 /etc/cryptfs.key
+# swap /dev/sdx4 /dev/urandom swap,cipher=aes-cbc-essiv:sha256,size=256
+# vol /dev/sdb7 none
+cryptdata /dev/sda1 /luksKey
diff --git a/root/etc/default/grub b/root/etc/default/grub
new file mode 100644
index 0000000..e337efd
--- /dev/null
+++ b/root/etc/default/grub
@@ -0,0 +1,73 @@
+# GRUB boot loader configuration
+
+GRUB_DEFAULT=0
+GRUB_TIMEOUT=5
+GRUB_DISTRIBUTOR="Arch"
+GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet"
+
+# Since we're using encrypted root, during grub's configuration creation, it can
+# only pick up on the UUID of the current (already encrypted) root, i.e. the mapper device.
+# For that reason, we instead specify the UUID of our actual physical (encrypted) partition
+# here ourselves. We then specify the name for the mapper device, and additional options.
+# Specifically, we set allow-discards, which is here for SSD optimizations.
+#
+# Handling the decryption of this device will then be delegated to initramfs. Note that we do
+# need to add the encrypt hook, along with some other hooks (like keyboard) to our mkinitcpio
+# so that our initramfs will actually be able to prompt us for this password.
+GRUB_CMDLINE_LINUX="cryptdevice=UUID=1864bad3-7e73-415a-a36d-49d941eb98c2:cryptroot:allow-discards"
+
+# Preload both GPT and MBR modules so that they are not missed
+GRUB_PRELOAD_MODULES="part_gpt part_msdos"
+
+# Uncomment to enable booting from LUKS encrypted /boot partition
+#GRUB_ENABLE_CRYPTODISK=y
+
+# Set to 'countdown' or 'hidden' to change timeout behavior,
+# press ESC key to display menu.
+GRUB_TIMEOUT_STYLE=menu
+
+# Uncomment to use basic console
+GRUB_TERMINAL_INPUT=console
+
+# Uncomment to disable graphical terminal
+#GRUB_TERMINAL_OUTPUT=console
+
+# The resolution used on graphical terminal
+# note that you can use only modes which your graphic card supports via VBE
+# you can see them in real GRUB with the command `vbeinfo'
+GRUB_GFXMODE=auto
+
+# Uncomment to allow the kernel use the same resolution used by grub
+GRUB_GFXPAYLOAD_LINUX=keep
+
+# Uncomment if you want GRUB to pass to the Linux kernel the old parameter
+# format "root=/dev/xxx" instead of "root=/dev/disk/by-uuid/xxx"
+#GRUB_DISABLE_LINUX_UUID=true
+
+# Uncomment to disable generation of recovery mode menu entries
+GRUB_DISABLE_RECOVERY=true
+
+# Uncomment and set to the desired menu colors. Used by normal and wallpaper
+# modes only. Entries specified as foreground/background.
+#GRUB_COLOR_NORMAL="light-blue/black"
+#GRUB_COLOR_HIGHLIGHT="light-cyan/blue"
+
+# Uncomment one of them for the gfx desired, a image background or a gfxtheme
+#GRUB_BACKGROUND="/path/to/wallpaper"
+#GRUB_THEME="/path/to/gfxtheme"
+
+# Uncomment to get a beep at GRUB start
+#GRUB_INIT_TUNE="480 440 1"
+
+# Uncomment to make GRUB remember the last selection. This requires
+# setting 'GRUB_DEFAULT=saved' above.
+#GRUB_SAVEDEFAULT=true
+
+# Uncomment to disable submenus in boot menu
+#GRUB_DISABLE_SUBMENU=y
+
+# Probing for other operating systems is disabled for security reasons. Read
+# documentation on GRUB_DISABLE_OS_PROBER, if still want to enable this
+# functionality install os-prober and uncomment to detect and include other
+# operating systems.
+#GRUB_DISABLE_OS_PROBER=false
diff --git a/root/etc/modprobe.d/blacklist-noveau.conf b/root/etc/modprobe.d/blacklist-noveau.conf
new file mode 100644
index 0000000..67c5630
--- /dev/null
+++ b/root/etc/modprobe.d/blacklist-noveau.conf
@@ -0,0 +1,2 @@
+blacklist noveau
+options noveau modeset=0
diff --git a/root/etc/modprobe.d/nobeep.conf b/root/etc/modprobe.d/nobeep.conf
new file mode 100644
index 0000000..b46792e
--- /dev/null
+++ b/root/etc/modprobe.d/nobeep.conf
@@ -0,0 +1 @@
+blacklist pcspkr
diff --git a/root/etc/pacman.conf b/root/etc/pacman.conf
new file mode 100644
index 0000000..59b1836
--- /dev/null
+++ b/root/etc/pacman.conf
@@ -0,0 +1,105 @@
+#
+# /etc/pacman.conf
+#
+# See the pacman.conf(5) manpage for option and repository directives
+
+#
+# GENERAL OPTIONS
+#
+[options]
+# The following paths are commented out with their default values listed.
+# If you wish to use different paths, uncomment and update the paths.
+#RootDir = /
+#DBPath = /var/lib/pacman/
+#CacheDir = /var/cache/pacman/pkg/
+#LogFile = /var/log/pacman.log
+#GPGDir = /etc/pacman.d/gnupg/
+#HookDir = /etc/pacman.d/hooks/
+HoldPkg = pacman glibc
+#XferCommand = /usr/bin/curl -L -C - -f -o %o %u
+#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
+#CleanMethod = KeepInstalled
+Architecture = auto
+
+# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
+#IgnorePkg =
+#IgnoreGroup =
+
+#NoUpgrade =
+#NoExtract =
+
+# Misc options
+#UseSyslog
+Color
+CheckSpace
+VerbosePkgLists
+#DisableDownloadTimeout
+#ILoveCandy
+ParallelDownloads = 8
+
+# By default, pacman accepts packages signed by keys that its local keyring
+# trusts (see pacman-key and its man page), as well as unsigned packages.
+SigLevel = Required DatabaseOptional
+LocalFileSigLevel = Optional
+#RemoteFileSigLevel = Required
+
+# NOTE: You must run `pacman-key --init` before first using pacman; the local
+# keyring can then be populated with the keys of all official Arch Linux
+# packagers with `pacman-key --populate archlinux`.
+
+#
+# REPOSITORIES
+# - can be defined here or included from another file
+# - pacman will search repositories in the order defined here
+# - local/custom mirrors can be added here or in separate files
+# - repositories listed first will take precedence when packages
+# have identical names, regardless of version number
+# - URLs will have $repo replaced by the name of the current repo
+# - URLs will have $arch replaced by the name of the architecture
+#
+# Repository entries are of the format:
+# [repo-name]
+# Server = ServerName
+# Include = IncludePath
+#
+# The header [repo-name] is crucial - it must be present and
+# uncommented to enable the repo.
+#
+
+# The testing repositories are disabled by default. To enable, uncomment the
+# repo name header and Include lines. You can add preferred servers immediately
+# after the header, and they will be used before the default mirrors.
+
+# Use blackarch first, so that other indices can take precedence in
+# versions, usually core/extra/community/multilib have newer versions
+# in comparison to blackarch index
+#[testing]
+#Include = /etc/pacman.d/mirrorlist
+
+[core]
+Include = /etc/pacman.d/mirrorlist
+
+[extra]
+Include = /etc/pacman.d/mirrorlist
+
+#[community-testing]
+#Include = /etc/pacman.d/mirrorlist
+
+[community]
+Include = /etc/pacman.d/mirrorlist
+
+# If you want to run 32 bit applications on your x86_64 system,
+# enable the multilib repositories as required here.
+
+#[multilib-testing]
+#Include = /etc/pacman.d/mirrorlist
+
+[multilib]
+Include = /etc/pacman.d/mirrorlist
+
+# An example of a custom package repository. See the pacman manpage for
+# tips on creating your own repositories.
+#[custom]
+#SigLevel = Optional TrustAll
+#Server = file:///home/custompkgs
+
diff --git a/root/etc/pipewire/pipewire-pulse.conf b/root/etc/pipewire/pipewire-pulse.conf
new file mode 100644
index 0000000..2e9bb0d
--- /dev/null
+++ b/root/etc/pipewire/pipewire-pulse.conf
@@ -0,0 +1,11 @@
+pulse.rules = [
+ {
+ # Discord notification sounds fix
+ matches = [ { application.process.binary = "Discord" } ]
+ actions = {
+ update-props = {
+ pulse.min.quantum = 1024/48000 # 21ms
+ }
+ }
+ }
+}
diff --git a/root/etc/sudoers b/root/etc/sudoers
new file mode 100644
index 0000000..e04b581
--- /dev/null
+++ b/root/etc/sudoers
@@ -0,0 +1,99 @@
+## sudoers file.
+##
+## This file MUST be edited with the 'visudo' command as root.
+## Failure to use 'visudo' may result in syntax or file permission errors
+## that prevent sudo from running.
+##
+## See the sudoers man page for the details on how to write a sudoers file.
+##
+
+##
+## Host alias specification
+##
+## Groups of machines. These may include host names (optionally with wildcards),
+## IP addresses, network numbers or netgroups.
+# Host_Alias WEBSERVERS = www1, www2, www3
+
+##
+## User alias specification
+##
+## Groups of users. These may consist of user names, uids, Unix groups,
+## or netgroups.
+# User_Alias ADMINS = millert, dowdy, mikef
+
+##
+## Cmnd alias specification
+##
+## Groups of commands. Often used to group related commands together.
+# Cmnd_Alias PROCESSES = /usr/bin/nice, /bin/kill, /usr/bin/renice, \
+# /usr/bin/pkill, /usr/bin/top
+# Cmnd_Alias REBOOT = /sbin/halt, /sbin/reboot, /sbin/poweroff
+
+##
+## Defaults specification
+##
+## You may wish to keep some of the following environment variables
+## when running commands via sudo.
+##
+## Locale settings
+# Defaults env_keep += "LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET"
+##
+## Run X applications through sudo; HOME is used to find the
+## .Xauthority file. Note that other programs use HOME to find
+## configuration files and this may lead to privilege escalation!
+# Defaults env_keep += "HOME"
+##
+## X11 resource path settings
+# Defaults env_keep += "XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH"
+##
+## Desktop path settings
+# Defaults env_keep += "QTDIR KDEDIR"
+##
+## Allow sudo-run commands to inherit the callers' ConsoleKit session
+# Defaults env_keep += "XDG_SESSION_COOKIE"
+##
+## Uncomment to enable special input methods. Care should be taken as
+## this may allow users to subvert the command being run via sudo.
+# Defaults env_keep += "XMODIFIERS GTK_IM_MODULE QT_IM_MODULE QT_IM_SWITCHER"
+##
+## Uncomment to use a hard-coded PATH instead of the user's to find commands
+# Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+##
+## Uncomment to send mail if the user does not enter the correct password.
+# Defaults mail_badpass
+##
+## Uncomment to enable logging of a command's output, except for
+## sudoreplay and reboot. Use sudoreplay to play back logged sessions.
+Defaults log_output
+Defaults!/usr/bin/sudoreplay !log_output
+Defaults!/usr/local/bin/sudoreplay !log_output
+Defaults!REBOOT !log_output
+
+# Add some fine insults
+Defaults insults
+
+##
+## Runas alias specification
+##
+
+##
+## User privilege specification
+##
+root ALL=(ALL) ALL
+
+## Uncomment to allow members of group wheel to execute any command
+%wheel ALL=(ALL) ALL
+
+## Same thing without a password
+# %wheel ALL=(ALL) NOPASSWD: ALL
+
+## Uncomment to allow members of group sudo to execute any command
+# %sudo ALL=(ALL) ALL
+
+## Uncomment to allow any user to run sudo if they know the password
+## of the user they are running the command as (root by default).
+# Defaults targetpw # Ask for the password of the target user
+# ALL ALL=(ALL) ALL # WARNING: only use this together with 'Defaults targetpw'
+
+## Read drop-in files from /etc/sudoers.d
+@includedir /etc/sudoers.d
diff --git a/root/etc/sudoers.d/brightness-mod b/root/etc/sudoers.d/brightness-mod
new file mode 100644
index 0000000..75dd592
--- /dev/null
+++ b/root/etc/sudoers.d/brightness-mod
@@ -0,0 +1,2 @@
+ALL ALL=(ALL) NOPASSWD: /usr/bin/tee /sys/class/backlight/intel_backlight/brightness
+
diff --git a/root/etc/sudoers.d/poweroff b/root/etc/sudoers.d/poweroff
new file mode 100644
index 0000000..73ae525
--- /dev/null
+++ b/root/etc/sudoers.d/poweroff
@@ -0,0 +1,4 @@
+ALL ALL=(ALL) NOPASSWD: /sbin/poweroff
+ALL ALL=(ALL) NOPASSWD: /sbin/shutdown
+ALL ALL=(ALL) NOPASSWD: /sbin/reboot
+
diff --git a/root/etc/systemd/system/paccache.timer b/root/etc/systemd/system/paccache.timer
new file mode 100644
index 0000000..6528cb7
--- /dev/null
+++ b/root/etc/systemd/system/paccache.timer
@@ -0,0 +1,14 @@
+# Clean pacman cache of old and uninstalled packages every month
+# This needs to be started by running `systemctl start paccache.timer`
+# Usage requires `pacman-contrib` package to be installed
+
+[Unit]
+Description=Clean-up old pacman pkg
+
+[Timer]
+OnCalendar=weekly
+AccuracySec=1h
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/root/usr/local/src/Hyprland b/root/usr/local/src/Hyprland
new file mode 160000
index 0000000..d994ad7
--- /dev/null
+++ b/root/usr/local/src/Hyprland
@@ -0,0 +1 @@
+Subproject commit d994ad75e80df6c97c400f85e0fbdf11dbb5ca49
diff --git a/root/usr/local/src/eww b/root/usr/local/src/eww
new file mode 160000
index 0000000..7a0e1b7
--- /dev/null
+++ b/root/usr/local/src/eww
@@ -0,0 +1 @@
+Subproject commit 7a0e1b77f24ee89d627e552f9abc55eb636aaaa6
diff --git a/root/usr/local/src/z.lua b/root/usr/local/src/z.lua
new file mode 160000
index 0000000..0992ebf
--- /dev/null
+++ b/root/usr/local/src/z.lua
@@ -0,0 +1 @@
+Subproject commit 0992ebf9f1f6cdaa114e65d3aa76bfb1bd9a6fd4
diff --git a/root/usr/share/zsh/site-functions/zsh-autosuggestions b/root/usr/share/zsh/site-functions/zsh-autosuggestions
new file mode 160000
index 0000000..a411ef3
--- /dev/null
+++ b/root/usr/share/zsh/site-functions/zsh-autosuggestions
@@ -0,0 +1 @@
+Subproject commit a411ef3e0992d4839f0732ebeb9823024afaaaa8
diff --git a/root/usr/share/zsh/site-functions/zsh-syntax-highlighting b/root/usr/share/zsh/site-functions/zsh-syntax-highlighting
new file mode 160000
index 0000000..122dc46
--- /dev/null
+++ b/root/usr/share/zsh/site-functions/zsh-syntax-highlighting
@@ -0,0 +1 @@
+Subproject commit 122dc464392302114556b53ec01a1390c54f739f
diff --git a/root/usr/share/zsh/site-functions/zsh-you-should-use b/root/usr/share/zsh/site-functions/zsh-you-should-use
new file mode 160000
index 0000000..13c8635
--- /dev/null
+++ b/root/usr/share/zsh/site-functions/zsh-you-should-use
@@ -0,0 +1 @@
+Subproject commit 13c86356553b80e0e0cbf1ecf6d82cfa79751b5a
diff --git a/sync.py b/sync.py
new file mode 100755
index 0000000..ad5e83a
--- /dev/null
+++ b/sync.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python
+from __future__ import annotations
+
+import hashlib
+import sys
+from collections.abc import Iterable, Iterator
+from enum import Enum, auto
+from pathlib import Path
+from typing import NamedTuple
+
+try:
+ import rich
+except ImportError:
+ print("rich not found (`pip install rich`), falling back to no colors", file=sys.stderr)
+ rich = None
+
+DOTHOMEDIR = Path("./home")
+HOMEDIR = Path("~")
+DOTROOTDIR = Path("./root")
+ROOTDIR = Path("/")
+
+
+class DiffStatus(Enum):
+ NOT_FOUND = auto()
+ PERMISSION_ERROR = auto()
+ MATCH = auto()
+ EXPECTED_SYMLINK = auto()
+ UNEXPECTED_SYMLINK = auto()
+ CONTENT_DIFFERS = auto()
+ SYMLINK_DIFFERS = auto()
+
+
+class FileDiff(NamedTuple):
+ dot_file: Path
+ sys_file: Path
+ status: DiffStatus
+
+ def __repr__(self) -> str:
+ dot_file = str(self.rel_dot_file)
+ sys_file = str(self.sys_file)
+ status = self.status.name
+ return f"FileDiff({dot_file=}, {sys_file=}, {status=})"
+
+ @property
+ def rel_dot_file(self) -> Path:
+ """Returns path to a dot_file relative to workdir."""
+ return self.dot_file.relative_to(Path.cwd())
+
+
+def iter_dir(directory: Path) -> Iterator[Path]:
+ """Recursively iterate over given directory and yield all files in it."""
+ for subpath in directory.iterdir():
+ if subpath.is_file() or subpath.is_symlink():
+ yield subpath
+ else:
+ yield from iter_dir(subpath)
+
+
+def file_sum(file: Path) -> str:
+ """Compute SHA-256 hash sum of given file."""
+ sha256_hash = hashlib.sha256()
+ with file.open("rb") as f:
+ for byte_block in iter(lambda: f.read(4096), b""):
+ sha256_hash.update(byte_block)
+ return sha256_hash.hexdigest()
+
+
+def compare_files(dot_file: Path, sys_file: Path) -> DiffStatus:
+ """Compare two files returning their diff status."""
+ try:
+ if not sys_file.exists():
+ return DiffStatus.NOT_FOUND
+ except PermissionError:
+ return DiffStatus.PERMISSION_ERROR
+
+ if dot_file.is_symlink():
+ if sys_file.is_symlink():
+ if dot_file.readlink() == sys_file.readlink():
+ return DiffStatus.MATCH
+ else:
+ # In case the sys_file link uses an absolute path, make sure
+ # it points to the same location, even if that location is a
+ # symlink.
+ dot_target = sys_file.parent.joinpath(dot_file.readlink()).absolute()
+ sys_target = sys_file.parent.joinpath(sys_file.readlink()).absolute()
+ if dot_target == sys_target:
+ return DiffStatus.MATCH
+ return DiffStatus.SYMLINK_DIFFERS
+ return DiffStatus.EXPECTED_SYMLINK
+ elif sys_file.is_symlink():
+ return DiffStatus.UNEXPECTED_SYMLINK
+
+ try:
+ if file_sum(dot_file) == file_sum(sys_file):
+ return DiffStatus.MATCH
+ except PermissionError:
+ return DiffStatus.PERMISSION_ERROR
+
+ return DiffStatus.CONTENT_DIFFERS
+
+
+def iter_pairs() -> Iterator[tuple[Path, Path]]:
+ """Go through all files in the dotfiles directories and match them to system paths.
+
+ Yields tuples of (dotfile file path, matching system path)
+ """
+ for dot_file in iter_dir(DOTHOMEDIR):
+ real_file = Path(HOMEDIR, *dot_file.parts[1:])
+ yield dot_file.expanduser().absolute(), real_file.expanduser().absolute()
+
+ for dot_file in iter_dir(DOTROOTDIR):
+ real_file = Path(ROOTDIR, *dot_file.parts[1:])
+ yield dot_file.expanduser().absolute(), real_file.expanduser().absolute()
+
+
+def iter_diffs() -> Iterator[FileDiff]:
+ """Go through all files and compute their diffs."""
+ for dot_file, sys_file in iter_pairs():
+ diff_status = compare_files(dot_file, sys_file)
+ yield FileDiff(dot_file, sys_file, diff_status)
+
+
+def print_status(diffs: Iterable[FileDiff]) -> None:
+ """Pretty print the individual diff statuses."""
+ # Exhause the iterable, and ensure we work on a copy
+ diffs = list(diffs)
+
+ # Sort by DiffStatus, with MATCH entries being first
+ diffs.sort(key=lambda v: (v.status is not DiffStatus.MATCH, v.status.name))
+
+ if rich is None:
+ for diff in diffs:
+ print(f"{diff.status.name} -> {diff.sys_file}")
+ return
+
+ from rich.table import Table
+ table = Table()
+ table.add_column("Status")
+ table.add_column("System file", style="magenta")
+ table.add_column("Dotfile file", style="magenta")
+
+ for diff in diffs:
+ _str_status = diff.status.name.replace("_", " ")
+ if diff.status is DiffStatus.MATCH:
+ status_str = (f"[green]{_str_status}[/green]")
+ elif diff.status is DiffStatus.PERMISSION_ERROR:
+ status_str = f"[bold yellow]{_str_status}[/bold yellow]"
+ elif diff.status is DiffStatus.NOT_FOUND:
+ status_str = f"[bold orange_red1]{_str_status}[/bold orange_red1]"
+ else:
+ status_str = f"[bold red]{_str_status}[/bold red]"
+
+ try:
+ # Unexpand home (/home/xyz/foo -> ~/foo)
+ sys_file = Path("~") / diff.sys_file.relative_to(Path.home())
+ except ValueError: # File not in home
+ sys_file = diff.sys_file
+
+ sys_file = str(sys_file)
+ dot_file = "./" + str(diff.rel_dot_file)
+ table.add_row(status_str, sys_file, dot_file)
+
+ rich.print(table)
+
+
+def exclude_fun(diff: FileDiff) -> bool:
+ EXCLUDE_RULES = [
+ lambda d: d.status is DiffStatus.MATCH,
+ lambda d: d.dot_file.name == ".keep" and d.sys_file.parent.is_dir(),
+ lambda d: Path("root/etc/opensnitchd/rules") in d.rel_dot_file.parents,
+ lambda d: Path("home/.config/xmobar") in d.rel_dot_file.parents,
+ lambda d: Path("home/.config/xmonad") in d.rel_dot_file.parents,
+ lambda d: Path("home/.local/share/xmonad") in d.rel_dot_file.parents,
+ lambda d: Path("home/.config/topgrade.toml") == d.rel_dot_file,
+ lambda d: Path("home/.config/newsboat") in d.rel_dot_file.parents,
+ lambda d: Path("home/.cache/zsh/history") == d.rel_dot_file and d.status is DiffStatus.CONTENT_DIFFERS,
+ lambda d: Path("home/.local/scripts") in d.rel_dot_file.parents, # Temporary
+ lambda d: Path("root") in d.rel_dot_file.parents, # Temporary
+ ]
+
+ for exc_rule in EXCLUDE_RULES:
+ if exc_rule(diff):
+ return False
+ return True
+
+
+def main() -> None:
+ diffs = iter_diffs()
+ diffs = filter(exclude_fun, diffs)
+ print_status(diffs)
+
+
+
+if __name__ == "__main__":
+ main()