Browse Source

clean history commit

Noah Vogt 3 năm trước cách đây
commit
b1fdd05384
100 tập tin đã thay đổi với 11337 bổ sung0 xóa
  1. 5 0
      .gitignore
  2. 674 0
      LICENSE
  3. 2 0
      README.md
  4. 17 0
      apply-dotfiles
  5. 52 0
      dot-config/X11/xinitrc
  6. 139 0
      dot-config/aliasrc
  7. 153 0
      dot-config/dunst/dunstrc
  8. 42 0
      dot-config/exportrc
  9. 11 0
      dot-config/gtk-2.0/gtkfilechooser.ini
  10. 2 0
      dot-config/gtk-2.0/settings.ini
  11. 5 0
      dot-config/gtk-3.0/bookmarks
  12. 2 0
      dot-config/gtk-3.0/settings.ini
  13. 2 0
      dot-config/gtk-4.0/settings.ini
  14. 4 0
      dot-config/lein/profiles.clj
  15. 111 0
      dot-config/lf/lfrc
  16. 109 0
      dot-config/llpp.conf
  17. 1 0
      dot-config/mpv/input.conf
  18. 52 0
      dot-config/newsboat/config
  19. 13 0
      dot-config/norisa.local.default
  20. 4 0
      dot-config/npm/npmrc
  21. 17 0
      dot-config/nvim/coc-settings.json
  22. 12 0
      dot-config/picom.conf
  23. 2 0
      dot-config/python/config
  24. 287 0
      dot-config/ranger/rifle.conf
  25. 16 0
      dot-config/readline/inputrc
  26. BIN
      dot-config/redyt/redyt.png
  27. 13 0
      dot-config/redyt/subreddits
  28. 20 0
      dot-config/setup/templates/latex/beamer.tex
  29. 30 0
      dot-config/setup/templates/latex/flowchart.tex
  30. 10 0
      dot-config/setup/templates/latex/nb
  31. 10 0
      dot-config/setup/templates/latex/nf
  32. 60 0
      dot-config/setup/templates/latex/school-template.tex
  33. 10 0
      dot-config/setup/templates/latex/sl
  34. 105 0
      dot-config/setup/templates/pandoc/dark-website.html
  35. 551 0
      dot-config/setup/templates/pandoc/english.latex
  36. 551 0
      dot-config/setup/templates/pandoc/french.latex
  37. 527 0
      dot-config/setup/templates/pandoc/german-draft.latex
  38. 557 0
      dot-config/setup/templates/pandoc/german.latex
  39. BIN
      dot-config/setup/templates/xournalpp/dotted.xopp
  40. 9 0
      dot-config/setup/templates/xournalpp/nx
  41. 15 0
      dot-config/user-dirs.dirs
  42. 2788 0
      dot-config/vim/autoload/plug.vim
  43. 2788 0
      dot-config/vim/plug.vim
  44. 257 0
      dot-config/vim/vimrc
  45. 85 0
      dot-config/xbindkeys/config
  46. 81 0
      dot-config/zsh/.zshrc
  47. 24 0
      local-bin/addpushremote
  48. 12 0
      local-bin/automine-toggle
  49. 15 0
      local-bin/battery
  50. 8 0
      local-bin/brightness
  51. 8 0
      local-bin/brightness-save
  52. 123 0
      local-bin/bv
  53. 22 0
      local-bin/compile
  54. 8 0
      local-bin/dec-brightness
  55. 14 0
      local-bin/dmenu-greek-letters-prompt
  56. 11 0
      local-bin/dmenu-java
  57. 68 0
      local-bin/dmenumount
  58. 5 0
      local-bin/dmenuprompt
  59. 44 0
      local-bin/dmenuumount
  60. 11 0
      local-bin/dmenuunicode
  61. 23 0
      local-bin/dyt
  62. 6 0
      local-bin/fcp
  63. 20 0
      local-bin/fetch-file-with-link
  64. 5 0
      local-bin/fixitunes
  65. 21 0
      local-bin/fnc
  66. 5 0
      local-bin/force-upstate
  67. 17 0
      local-bin/furryfox
  68. 6 0
      local-bin/get-date
  69. 12 0
      local-bin/get-single-token
  70. 6 0
      local-bin/get-uptime
  71. 12 0
      local-bin/get-volume
  72. 20 0
      local-bin/getnzz
  73. 7 0
      local-bin/gid
  74. 67 0
      local-bin/gkg-connect
  75. 9 0
      local-bin/glosscompile
  76. 8 0
      local-bin/inc-brightness
  77. 5 0
      local-bin/internal-ip
  78. 32 0
      local-bin/internet
  79. 7 0
      local-bin/list-mouses
  80. 9 0
      local-bin/low-battery-power-shutdown
  81. 11 0
      local-bin/mal-comment-scraper
  82. 67 0
      local-bin/memeatlas-sync
  83. 16 0
      local-bin/mkjar
  84. 17 0
      local-bin/mouse-acceleration
  85. 3 0
      local-bin/mp3pls
  86. 75 0
      local-bin/nmine
  87. 36 0
      local-bin/reapk
  88. 67 0
      local-bin/redyt
  89. 5 0
      local-bin/rssyt
  90. 62 0
      local-bin/rsy
  91. 11 0
      local-bin/screencast-24
  92. 11 0
      local-bin/screencast-60
  93. 7 0
      local-bin/screenshot
  94. 7 0
      local-bin/screenshot-area
  95. 24 0
      local-bin/scripted-mouse-acceleration
  96. 10 0
      local-bin/st-exec
  97. 7 0
      local-bin/st-exec-sub
  98. 7 0
      local-bin/stop-rec
  99. 14 0
      local-bin/texclear
  100. 9 0
      local-bin/toggle-picom

+ 5 - 0
.gitignore

@@ -0,0 +1,5 @@
+.zcompdump
+dot-config/norisa.local
+dot-config/newsboat/urls
+dot-config/Xauth/auth
+local-share/gnupg/

+ 674 - 0
LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ 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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 <https://www.gnu.org/licenses/>.
+
+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:
+
+    <program>  Copyright (C) <year>  <name of author>
+    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
+<https://www.gnu.org/licenses/>.
+
+  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
+<https://www.gnu.org/licenses/why-not-lgpl.html>.

+ 2 - 0
README.md

@@ -0,0 +1,2 @@
+# dotfiles
+My Personal Dotfiles, LaTeX Templates and Scripts.

+ 17 - 0
apply-dotfiles

@@ -0,0 +1,17 @@
+#!/bin/sh
+
+#initDir=$(pwd)
+#confDirs=$(find dot-config/ -type d | tail -n +2)
+#for sourceDir in $confDirs; do
+    #targetDir=$(echo $sourceDir | sed 's/^dot-config/~\/\.config/g')
+    #[ -d "$targetDir" ] && mkdir -p "$targetDir"
+    #cd "${sourceDir%/*}"
+    #stow --verbose --dotfiles --target="$targetDir" "${sourceDir##*/}"
+    #cd "$initDir"
+#done
+
+stow --verbose --dotfiles --target=$HOME/.config dot-config
+stow --verbose --dotfiles --target=$HOME/.local/share local-share
+stow --verbose --dotfiles --target=$HOME/.local/bin local-bin
+#cd dot-config/
+#stow --verbose --dotfiles --target=$HOME/.config/vim vim

+ 52 - 0
dot-config/X11/xinitrc

@@ -0,0 +1,52 @@
+#!/bin/sh
+
+# set keyboard layout to Swiss German
+setxkbmap ch
+
+# start hotkey daemon
+xbindkeys -f "$XDG_CONFIG_HOME"/xbindkeys/config &
+
+feh --bg-scale --no-fehbg "$XDG_DATA_HOME"/norisa/black.jpg
+
+# turn off BIOS beeper
+xset b off
+
+# set WM name (for Java apps)
+wmname LG3D
+
+# load notification deamon
+dunst &
+
+# load composite manager
+picom &
+
+# swap caps and escape (for vim users)
+setxkbmap -option caps:swapescape
+
+# set brightness
+brightnessctl -d $(brightnessctl -l | grep "class 'backlight'" | head -n 1 | awk '{print $2}' | tr -d "'") set $(cat ~/.config/norisa/brightness-state)%
+
+# load dwmblocks
+dwmblocks &
+
+# don't display mouse if not used recently
+unclutter &
+
+# apply local config
+localconfig="${XDG_CONFIG_HOME:-$HOME/.config}/norisa.local"
+if [ -f "$localconfig" ]; then
+    . "$localconfig"
+    [ -z "$NORISA_XORG_MOUSE_ID" ] || scripted-mouse-acceleration \
+        "$NORISA_XORG_MOUSE_ID" &
+    [ -z "$NORISA_DISPLAYSETUP" ] || $NORISA_DISPLAYSETUP
+fi
+
+# set (previous) wallpaper
+~/.cache/.fehbg && mv ~/.fehbg ~/.cache
+
+# start pulseaudio when unable to fetch the volume
+volume=$(amixer sget Master | grep 'Front Left:' | awk -F '[\\]\\[]' '{print $2}')
+[ -z "$volume" ] && pulseaudio &
+
+# run dwm
+exec dwm

+ 139 - 0
dot-config/aliasrc

@@ -0,0 +1,139 @@
+# adding some colors to the world
+alias ls='ls --color=auto'
+alias grep='grep --color=auto'
+alias ccat='highlight --out-format=ansi' # like cat, but w/ syntax highlighting
+alias diff='diff --color=auto'
+
+# human readable pls
+alias du='du -h'
+alias df='df -h'
+alias free='free -h'
+
+# basic system aliases
+alias p='doas pacman'
+alias sc='doas systemctl'
+alias sdn='shutdown now > /dev/null 2> /dev/null || doas /usr/bin/openrc-shutdown --poweroff now'
+alias sus='systemctl suspend || loginctl suspend'
+alias re='reboot || doas openrc-shutdown --reboot now '
+alias q='exit'
+alias sx='startx "$XDG_CONFIG_HOME/X11/xinitrc" --'
+alias ll='ls -l'
+alias la='ls -A'
+alias resource='source ${ZDOTDIR:-$HOME}/.zshrc'
+
+# frequently used programs aliases
+alias r='ranger'
+alias ca='calcurse'
+alias py='python'
+#alias wget='wget --hsts-file ~/.cache/wget/wget-hsts'
+alias si='devour sxiv'
+alias lo='devour libreoffice'
+alias mu='devour mupdf'
+alias llp='devour llpp'
+alias nb='newsboat'
+alias mutt='neomutt'
+
+# copy and paste using xclip package
+alias copy="xclip -sel clip"
+alias paste="xclip -out -sel clip"
+
+# lockscreen
+alias lock='betterlockscreen -s dim'
+
+# faster directory switching
+alias ..='cd ..'
+alias ...='cd ../..'
+alias ....='cd ../../..'
+alias .....='cd ../../../..'
+
+# vim, v -> neovim
+alias vim='nvim'
+alias v='vim'
+
+# set background
+setbg() {
+    feh --bg-scale "$1"
+    [ -f "$HOME/.fehbg" ] && mv "$HOME/.fehbg" "$XDG_CACHE_HOME" && bv -u
+}
+
+# safety features
+alias rm='rm -i'
+alias cp='cp -i'
+alias mv='mv -i'
+
+# git aliases
+alias gsetkey="git config --add --local core.sshCommand 'ssh -i \$GIT_SSH_KEY'"
+alias clone="git clone -c core.sshCommand='/usr/bin/ssh -i \$GIT_SSH_KEY'"
+alias gs='git status'
+alias gd='git diff'
+alias add='git add'
+alias commit='git commit'
+alias fetch='git fetch'
+alias pull='git pull'
+alias push='git push'
+alias log='git log'
+alias remote='git remote'
+alias tag='git tag'
+alias checkout='git checkout'
+alias merge='git merge'
+alias branch='git branch'
+alias lsc='git log --graph --oneline --decorate --all'
+alias lsb="git log --graph --simplify-by-decoration --pretty=format:'%d' --all"
+alias lst="git log --graph --decorate --all --date=short --abbrev-commit --oneline --pretty=format:'%h%x09%an%x09%ad%x09%s'"
+
+# ~/ cleanup
+alias yarn="yarn --use-yarnrc $XDG_CONFIG_HOME/yarn/config"
+alias xbindkeys="xbindkeys -f $XDG_CONFIG_HOME/xbindkeys/config"
+alias abook="abook --config $XDG_CONFIG_HOME/abook/abookrc --datafile $XDG_DATA_HOME/abook/addressbook"
+
+# always open st in non-interactive mode
+alias nst="st > /dev/null 2> /dev/null &disown"
+
+# sane ytdl shortcuts
+alias yt="youtube-dl --add-metadata -i"
+alias yta="yt -x -f bestaudio/best"
+
+# imagemagick shortcuts
+alias dpi="identify -format '%x\n' -units PixelsPerInch"
+
+alias rmexif="exiftool -overwrite_original -all="
+
+# fast dir switching
+s() {
+    cd "$(ls -d ~/.local/src/* | fzf)"
+}
+
+b() {
+    file="$(ls ~/.local/bin/* | fzf)"
+    [ -n "$file" ] && "$EDITOR" "$file"
+}
+
+c() {
+    pushd "$HOME/.local/src/dotfiles" > /dev/null || exit 1
+    file="$(find dot-config -type f | fzf)"
+    [ -n "$file" ] && 
+        "$EDITOR" "${file/dot-config\//${XDG_CONFIG_HOME:-$HOME/.config}/}"
+    popd > /dev/null
+}
+
+# useful extended system aliases
+alias perm="stat -c \"%a %n\" --"
+installedsize() {
+    pacman -Qi | egrep '^(Name|Installed)' | cut -f2 -d':' | sed 's/^ //' | \
+    grep -A1 "$1" | grep -v "\-\-" | \
+    awk '{ printf "%s%s", $0, (NR%2==1 ? FS : RS) }' | column -t
+}
+etouch() {
+    [ -n "$1" ] && touch "$1" chmod +x "$1"
+}
+evim() {
+    [ -n "$1" ] && touch "$1" && chmod +x "$1" && v "$1"
+}
+mkcd() {
+    [ -n "$1" ] && mkdir "$1" && cd "$1"
+}
+
+# more non-system essential aliases
+djangokeygen() { python -c 'from django.core.management.utils import get_random_secret_key; \
+    print(get_random_secret_key())' || pip install django
+}

+ 153 - 0
dot-config/dunst/dunstrc

@@ -0,0 +1,153 @@
+[global]
+    monitor = 0
+    follow = keyboard
+    geometry = "350x5-0+24"
+    indicate_hidden = yes
+    shrink = yes
+    transparency = 20
+    notification_height = 0
+    separator_height = 2
+    padding = 0
+    horizontal_padding = 8
+    frame_width = 3
+    frame_color = "#282828"
+
+    # 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
+
+    idle_threshold = 120
+    font = Monospace 14
+    line_height = 0
+    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 = "<b>%s</b>\n%b"
+
+    alignment = left
+    show_age_threshold = 60
+    word_wrap = yes
+    ellipsize = middle
+    ignore_newline = no
+    stack_duplicates = true
+    hide_duplicate_count = true
+    show_indicators = yes
+    icon_position = left
+    max_icon_size = 40
+    icon_path = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/:/usr/share/icons/Adwaita/256x256/status/
+    sticky_history = yes
+    history_length = 20
+    dmenu = /usr/bin/dmenu -p dunst:
+    browser = /usr/bin/firefox -new-tab
+
+    # Always run rule-defined scripts, even if the notification is suppressed
+    always_run_script = true
+
+    title = Dunst
+    class = Dunst
+    startup_notification = false
+    force_xinerama = false
+[experimental]
+    per_monitor_dpi = false
+
+[shortcuts]
+    close = ctrl+space
+    close_all = ctrl+shift+space
+    history = ctrl++shift+h
+    context = ctrl+shift+period
+
+[urgency_low]
+    # IMPORTANT: colors have to be defined in quotation marks.
+    # Otherwise the "#" and following would be interpreted as a comment.
+    background = "#282828"
+    foreground = "#928374"
+    timeout = 5
+    # Icon for notifications with low urgency, uncomment to enable
+    #icon = /path/to/icon
+
+[urgency_normal]
+    background = "#458588"
+    foreground = "#ebdbb2"
+    timeout = 5
+
+[urgency_critical]
+    background = "#cc2421"
+    foreground = "#ebdbb2"
+    frame_color = "#fabd2f"
+    timeout = 0
+
+# 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", "summary", "body", "icon", "category",
+# "msg_urgency" and you can override the "timeout", "urgency", "foreground",
+# "background", "new_icon" and "format".
+# Shell-like globbing will get expanded.
+#
+# 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: if you don't want a notification to be displayed, set the format
+# to "".
+# NOTE: It might be helpful to run dunst -print in a terminal in order
+# to find fitting options for rules.
+
+#[espeak]
+#    summary = "*"
+#    script = dunst_espeak.sh
+
+#[script-test]
+#    summary = "*script*"
+#    script = dunst_test.sh
+
+#[ignore]
+#    # This notification will not be displayed
+#    summary = "foobar"
+#    format = ""
+
+#[history-ignore]
+#    # This notification will not be saved in history
+#    summary = "foobar"
+#    history_ignore = 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
+#
+# vim: ft=cfg
+

+ 42 - 0
dot-config/exportrc

@@ -0,0 +1,42 @@
+# setting basic variables
+export EDITOR=nvim
+export VISUAL=nvim
+export BROWSER=chromium
+export PATH=$PATH:~/.local/bin
+export SHELL=/bin/zsh
+
+# set XDG directories
+export XDG_CONFIG_HOME="$HOME/.config"
+export XDG_DATA_HOME="$HOME/.local/share"
+export XDG_CACHE_HOME="$HOME/.cache"
+
+# default git ssh key location
+export GIT_SSH_KEY="$XDG_CONFIG_HOME/ssh/id_rsa"
+
+# ~/ cleanup
+export VIMINIT="set nocp | source $XDG_CONFIG_HOME/vim/vimrc"
+export LESSHISTFILE='-'
+export XAUTHORITY="$XDG_RUNTIME_DIR/xauth"
+export INPUTRC="$XDG_CONFIG_HOME/readline/inputrc"
+export GTK2_RC_FILES="$XDG_CONFIG_HOME/gtk-2.0/gtkrc"
+export NPM_CONFIG_USERCONFIG="$XDG_CONFIG_HOME/npm/npmrc"
+export TERMINFO="$XDG_DATA_HOME/terminfo"
+export TERMINFO_DIRS="$XDG_DATA_HOME/terminfo:/usr/share/terminfo"
+export CARGO_HOME="$XDG_CACHE_HOME/cargo"
+export GOPATH="$XDG_DATA_HOME/go"
+export GNUPGHOME="${XDG_DATA_HOME:-$HOME/.local/share}/gnupg"
+export GRADLE_USER_HOME="$XDG_CACHE_HOME/gradle"
+export NPM_CONFIG_USERCONFIG="$XDG_CONFIG_HOME/npm/npmrc"
+export PASSWORD_STORE_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/pass"
+export PYTHONSTARTUP="$XDG_CONFIG_HOME/python/config"
+export LEIN_HOME="$XDG_DATA_HOME/lein"
+export CONAN_USER_HOME="$XDG_CONFIG_HOME"
+
+# quick acces to my latex templates 
+export PATH=$PATH:~/.config/setup/templates/latex
+
+# quick acces to my xournalpp templates 
+export PATH=$PATH:~/.config/setup/templates/xournalpp
+
+# fix android studio for dwm
+export _JAVA_AWT_WM_NONREPARENTING=1

+ 11 - 0
dot-config/gtk-2.0/gtkfilechooser.ini

@@ -0,0 +1,11 @@
+[Filechooser Settings]
+LocationMode=path-bar
+ShowHidden=true
+ShowSizeColumn=true
+GeometryX=486
+GeometryY=211
+GeometryWidth=948
+GeometryHeight=638
+SortColumn=name
+SortOrder=descending
+StartupMode=recent

+ 2 - 0
dot-config/gtk-2.0/settings.ini

@@ -0,0 +1,2 @@
+[Settings]
+gtk-application-prefer-dark-theme=1

+ 5 - 0
dot-config/gtk-3.0/bookmarks

@@ -0,0 +1,5 @@
+file:///home/based/dox
+file:///home/based/mus
+file:///home/based/pix
+file:///home/based/vids
+file:///home/based/dl

+ 2 - 0
dot-config/gtk-3.0/settings.ini

@@ -0,0 +1,2 @@
+[Settings]
+gtk-application-prefer-dark-theme=1

+ 2 - 0
dot-config/gtk-4.0/settings.ini

@@ -0,0 +1,2 @@
+[Settings]
+gtk-application-prefer-dark-theme=1

+ 4 - 0
dot-config/lein/profiles.clj

@@ -0,0 +1,4 @@
+{:user {:local-repo #=(eval (str (System/getenv "XDG_CACHE_HOME") "/m2"))
+        :repositories  {"local" {:url #=(eval (str "file://" (System/getenv "XDG_DATA_HOME") "/m2"))
+                                 :releases {:checksum :ignore}}}
+        }}

+ 111 - 0
dot-config/lf/lfrc

@@ -0,0 +1,111 @@
+# interpreter for shell commands (needs to be POSIX compatible)
+set shell sh
+
+# set '-eu' options for shell commands
+# These options are used to have safer shell commands. Option '-e' is used to
+# exit on error and option '-u' is used to give error for unset variables.
+# Option '-f' disables pathname expansion which can be useful when $f, $fs, and
+# $fx variables contain names with '*' or '?' characters. However, this option
+# is used selectively within individual commands as it can be limiting at
+# times.
+set shellopts '-eu'
+
+# set internal field separator (IFS) to "\n" for shell commands
+# This is useful to automatically split file names in $fs and $fx properly
+# since default file separator used in these variables (i.e. 'filesep' option)
+# is newline. You need to consider the values of these options and create your
+# commands accordingly.
+set ifs "\n"
+
+# leave some space at the top and the bottom of the screen
+set scrolloff 10
+
+# use enter for shell commands
+map <enter> shell
+
+# execute current file (must be executable)
+map x $$f
+map X !$f
+
+# dedicated keys for file opener actions
+map o &mimeopen $f
+map O $mimeopen --ask $f
+
+# custom fnc binding
+map b $~/.scripts/fnc $f
+
+# define a custom 'open' command
+# This command is called when current file is not a directory. You may want to
+# use either file extensions and/or mime types here. Below uses an editor for
+# text files and a file opener for the rest.
+cmd open ${{
+    case "${f##*.}" in
+		xopp) devour xournalpp $f;;
+        mp3) mpv $f;;
+		pdf) devour llpp $f > /dev/null 2> /dev/null &disown;;
+		epub) llpp $f > /dev/null 2> /dev/null &disown;;
+        sc) sc-im $f;;
+        *) 
+			case $(file --mime-type $f -b) in
+			text/*) $EDITOR $fx;;
+            image/*) sxiv $f &;;  
+            *) for f in $fx; do setsid $OPENER $f > /dev/null 2> /dev/null & done;;
+			esac;;
+    esac
+}}
+
+# define a custom 'rename' command without prompt for overwrite
+# cmd rename %[ -e $1 ] && printf "file exists" || mv $f $1
+# map r push :rename<space>
+
+# make sure trash folder exists
+# %mkdir -p ~/.trash
+
+# move current file or selected files to trash folder
+# (also see 'man mv' for backup/overwrite options)
+cmd trash %set -f; mv $fx ~/.trash
+
+# define a custom 'delete' command
+# cmd delete ${{
+#     set -f
+#     printf "$fx\n"
+#     printf "delete?[y/n]"
+#     read ans
+#     [ $ans = "y" ] && rm -rf $fx
+# }}
+
+# use '<delete>' key for either 'trash' or 'delete' command
+# map <delete> trash
+# map <delete> delete
+
+# extract the current file with the right command
+# (xkcd link: https://xkcd.com/1168/)
+cmd extract ${{
+    set -f
+    case $f in
+        *.tar.bz|*.tar.bz2|*.tbz|*.tbz2) tar xjvf $f;;
+        *.tar.gz|*.tgz) tar xzvf $f;;
+        *.tar.xz|*.txz) tar xJvf $f;;
+        *.zip) unzip $f;;
+        *.rar) unrar x $f;;
+        *.7z) 7z x $f;;
+    esac
+}}
+
+# compress current file or selected files with tar and gunzip
+cmd tar ${{
+    set -f
+    mkdir $1
+    cp -r $fx $1
+    tar czf $1.tar.gz $1
+    rm -rf $1
+}}
+
+# compress current file or selected files with zip
+cmd zip ${{
+    set -f
+    mkdir $1
+    cp -r $fx $1
+    zip -r $1.zip $1
+    rm -rf $1
+}}

+ 109 - 0
dot-config/llpp.conf

@@ -0,0 +1,109 @@
+<llppconfig>
+<ui-font size='20'/>
+<defaults
+    width='1200'
+    height='1000'
+    scroll-bar-width='7'
+    scroll-handle-height='12'
+    horizontal-scrollbar-visible='true'
+    vertical-scrollbar-visible='true'
+    case-insensitive-search='true'
+    preload='true'
+    page-bias='0'
+    scroll-step='24'
+    auto-scroll-step='12'
+    max-height-fit='true'
+    highlight-links='false'
+    under-cursor-info='false'
+    vertical-margin='2'
+    zoom='100'
+    presentation='false'
+    rotation-angle='0'
+    fit-model='proportional'
+    pixmap-cache-size='32M'
+    tex-count='256'
+    slice-height='24'
+    thumbnail-width='76'
+    background-color='127/127/127'
+    paper-color='255/255/255/0'
+    scrollbar-color='163/163/163/178'
+    scrollbar-handle-color='0/0/0/178'
+    texture-color='0/0/0/0'
+    tile-width='2048'
+    tile-height='2048'
+    mupdf-store-size='256M'
+    checkers='true'
+    aalevel='8'
+    trim-margins='false'
+    trim-fuzz='0/0/0/0'
+    uri-launcher='$BROWSER &quot;%s&quot;'
+    path-launcher='$TERMINAL &quot;%s&quot;'
+    color-space='rgb'
+    invert-colors='false'
+    brightness='1.000000'
+    selection-command='LC_CTYPE=UTF-8 xclip -i'
+    paste-command='LC_CTYPE=UTF-8 xclip -o'
+    synctex-command='echo SyncTex'
+    pax-command='cat'
+    askpass-command=''
+    savepath-command=''
+    update-cursor='true'
+    hint-font-size='12'
+    horizontal-scroll-step='24'
+    page-scroll-scale='1.000000'
+    use-pbo='false'
+    wheel-scrolls-pages='false'
+    remote-in-a-new-instance='false'
+    point-and-x='false'
+    point-and-x-mark='word'
+    scroll-bar-on-the-left='false'
+    last-visit='-9223372036854775808'
+    edit-annotations-inline='true'
+    coarse-presentation-positioning='false'
+    use-document-css='true'
+    dcf=''>
+<keymap mode='global'>
+<map in='ctrl-c' out='esc'/>
+<map in='ctrl-n' out='down'/>
+<map in='ctrl-p' out='up'/>
+<map in='ctrl-f' out='pgdown'/>
+<map in='ctrl-[' out='esc'/>
+<map in='ctrl-b' out='pgup'/>
+</keymap>
+<keymap mode='birdseye'>
+<map in='k' out='up'/>
+<map in='ctrl-u' out='ctrl-k'/>
+<map in='u' out='ctrl-k'/>
+<map in='l' out='right'/>
+<map in='j' out='down'/>
+<map in='f' out='pgdown'/>
+<map in='d' out='ctrl-j'/>
+<map in='f11' out='f'/>
+<map in='ctrl-d' out='ctrl-j'/>
+<map in='b' out='pgup'/>
+<map in='h' out='left'/>
+</keymap>
+<keymap mode='view'>
+<map in='tab' out='o'/>
+<map in='k' out='up'/>
+<map in='ctrl-u' out='ctrl-k'/>
+<map in='u' out='ctrl-k'/>
+<map in='l' out='right'/>
+<map in='j' out='down'/>
+<map in='f' out='pgdown'/>
+<map in='d' out='ctrl-j'/>
+<map in='f11' out='f'/>
+<map in='ctrl-d' out='ctrl-j'/>
+<map in='b' out='pgup'/>
+<map in='h' out='left'/>
+</keymap>
+</defaults>
+<doc path='/tmp/index.pdf'
+    key='4fdc2bf3b1abbaa90c8bfeaf3f8ff3f3'
+    page='1' rely='0.286853' pan='-218'
+    width='905'
+    height='980'
+    auto-scroll-step='0'
+    zoom='150'
+    last-visit='1616367773'/>
+</llppconfig>

+ 1 - 0
dot-config/mpv/input.conf

@@ -0,0 +1 @@
+c show-text "${chapter-list}"

+ 52 - 0
dot-config/newsboat/config

@@ -0,0 +1,52 @@
+browser "librewolf %u"
+
+# vim keybindings
+
+unbind-key j
+unbind-key k
+unbind-key h
+unbind-key H
+unbind-key L
+unbind-key c
+unbind-key ,
+
+bind-key ; macro-prefix
+bind-key h quit
+bind-key BACKSPACE quit
+bind-key j down
+bind-key k up
+bind-key l open
+bind-key H prev-feed
+bind-key L next-feed
+bind-key c toggle-show-read-feeds
+bind-key a toggle-article-read
+
+# macros
+
+macro l set browser "open-stream %u"; open-in-browser; set browser "librewolf %u"
+
+# Feed settings
+prepopulate-query-feeds yes
+refresh-on-startup no
+
+color background default default
+color listnormal default default
+color listnormal_unread default default
+color listfocus color16 cyan
+color listfocus_unread color16 cyan
+color info default black
+color article default default
+
+highlight article "(^Feed:.*|^Title:.*|^Author:.*)" cyan default bold
+highlight article "(^Link:.*|^Date:.*)" default default
+highlight article "https?://[^ ]+" green default
+
+highlight article "^(Title):.*$" blue default
+highlight article "\\[[0-9][0-9]*\\]" magenta default bold
+highlight article "\\[image\\ [0-9]+\\]" green default bold
+highlight article "\\[embedded flash: [0-9][0-9]*\\]" green default bold
+highlight article ":.*\\(link\\)$" cyan default
+highlight article ":.*\\(image\\)$" blue default
+highlight article ":.*\\(embedded flash\\)$" magenta default
+
+browser "librewolf %u"

+ 13 - 0
dot-config/norisa.local.default

@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# this is a the default configuration file which needs to be copied to 
+# $XDG_CONFIG_HOME/norisa.local to be active on a individual machine. It is
+# intended to provide the possibility of certain machine-specific configuration
+# options, while still enabling the machine-agnostic configuration to be synced
+# via the norisa dotfiles repository. This file should be ingnored by VCS.
+
+NORISA_DISPLAYSETUP="" # xrandr command to setup display settings
+
+NORISA_XORG_MOUSE_ID="" # mouse id on which to disable mouse acceleration
+
+VPS_REMOTE="" # remote vps git linkformat

+ 4 - 0
dot-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

+ 17 - 0
dot-config/nvim/coc-settings.json

@@ -0,0 +1,17 @@
+{
+  "languageserver": {
+    "ccls": {
+      "command": "ccls",
+      "filetypes": ["c", "cpp", "cuda", "objc", "objcpp"],
+      "rootPatterns": [".ccls-root", "compile_commands.json"],
+      "initializationOptions": {
+        "cache": {
+          "directory": "/tmp/ccls-cache"
+        },
+        "client": {
+          "snippetSupport": true
+        }
+      }
+    }
+  }
+}

+ 12 - 0
dot-config/picom.conf

@@ -0,0 +1,12 @@
+backend = "glx";
+vsync = true;
+unredir-if-possible = false;
+
+# enable client side shadows
+shadow = true;
+
+round-borders = 1;
+corner-radius = 15.0;
+rounded-corners-exclude = [
+  "class_g = 'dwm'"
+];

+ 2 - 0
dot-config/python/config

@@ -0,0 +1,2 @@
+import readline
+readline.write_history_file = lambda *args: None

+ 287 - 0
dot-config/ranger/rifle.conf

@@ -0,0 +1,287 @@
+# vim: ft=cfg
+#
+# This is the configuration file of "rifle", ranger's file executor/opener.
+# Each line consists of conditions and a command.  For each line the conditions
+# are checked and if they are met, the respective command is run.
+#
+# Syntax:
+#   <condition1> , <condition2> , ... = command
+#
+# The command can contain these environment variables:
+#   $1-$9 | The n-th selected file
+#   $@    | All selected files
+#
+# If you use the special command "ask", rifle will ask you what program to run.
+#
+# Prefixing a condition with "!" will negate its result.
+# These conditions are currently supported:
+#   match <regexp> | The regexp matches $1
+#   ext <regexp>   | The regexp matches the extension of $1
+#   mime <regexp>  | The regexp matches the mime type of $1
+#   name <regexp>  | The regexp matches the basename of $1
+#   path <regexp>  | The regexp matches the absolute path of $1
+#   has <program>  | The program is installed (i.e. located in $PATH)
+#   env <variable> | The environment variable "variable" is non-empty
+#   file           | $1 is a file
+#   directory      | $1 is a directory
+#   number <n>     | change the number of this command to n
+#   terminal       | stdin, stderr and stdout are connected to a terminal
+#   X              | A graphical environment is available (darwin, Xorg, or Wayland)
+#
+# There are also pseudo-conditions which have a "side effect":
+#   flag <flags>  | Change how the program is run. See below.
+#   label <label> | Assign a label or name to the command so it can
+#                 | be started with :open_with <label> in ranger
+#                 | or `rifle -p <label>` in the standalone executable.
+#   else          | Always true.
+#
+# Flags are single characters which slightly transform the command:
+#   f | Fork the program, make it run in the background.
+#     |   New command = setsid $command >& /dev/null &
+#   r | Execute the command with root permissions
+#     |   New command = sudo $command
+#   t | Run the program in a new terminal.  If $TERMCMD is not defined,
+#     | rifle will attempt to extract it from $TERM.
+#     |   New command = $TERMCMD -e $command
+# Note: The "New command" serves only as an illustration, the exact
+# implementation may differ.
+# Note: When using rifle in ranger, there is an additional flag "c" for
+# only running the current file even if you have marked multiple files.
+
+#-------------------------------------------
+# Websites
+#-------------------------------------------
+# Rarely installed browsers get higher priority; It is assumed that if you
+# install a rare browser, you probably use it.  Firefox/konqueror/w3m on the
+# other hand are often only installed as fallback browsers.
+ext x?html?, has surf,             X, flag f = surf -- file://"$1"
+ext x?html?, has vimprobable,      X, flag f = vimprobable -- "$@"
+ext x?html?, has vimprobable2,     X, flag f = vimprobable2 -- "$@"
+ext x?html?, has qutebrowser,      X, flag f = qutebrowser -- "$@"
+ext x?html?, has dwb,              X, flag f = dwb -- "$@"
+ext x?html?, has jumanji,          X, flag f = jumanji -- "$@"
+ext x?html?, has luakit,           X, flag f = luakit -- "$@"
+ext x?html?, has uzbl,             X, flag f = uzbl -- "$@"
+ext x?html?, has uzbl-tabbed,      X, flag f = uzbl-tabbed -- "$@"
+ext x?html?, has uzbl-browser,     X, flag f = uzbl-browser -- "$@"
+ext x?html?, has uzbl-core,        X, flag f = uzbl-core -- "$@"
+ext x?html?, has midori,           X, flag f = midori -- "$@"
+ext x?html?, has opera,            X, flag f = opera -- "$@"
+ext x?html?, has firefox,          X, flag f = firefox -- "$@"
+ext x?html?, has seamonkey,        X, flag f = seamonkey -- "$@"
+ext x?html?, has iceweasel,        X, flag f = iceweasel -- "$@"
+ext x?html?, has chromium-browser, X, flag f = chromium-browser -- "$@"
+ext x?html?, has chromium,         X, flag f = chromium -- "$@"
+ext x?html?, has google-chrome,    X, flag f = google-chrome -- "$@"
+ext x?html?, has epiphany,         X, flag f = epiphany -- "$@"
+ext x?html?, has konqueror,        X, flag f = konqueror -- "$@"
+ext x?html?, has elinks,            terminal = elinks "$@"
+ext x?html?, has links2,            terminal = links2 "$@"
+ext x?html?, has links,             terminal = links "$@"
+ext x?html?, has lynx,              terminal = lynx -- "$@"
+ext x?html?, has w3m,               terminal = w3m "$@"
+
+#-------------------------------------------
+# Misc
+#-------------------------------------------
+# Define the "editor" for text files as first action
+mime ^text,  label editor = ${VISUAL:-$EDITOR} -- "$@"
+mime ^text,  label pager  = "$PAGER" -- "$@"
+!mime ^text, label editor, ext xml|json|csv|tex|py|pl|rb|js|sh|php = ${VISUAL:-$EDITOR} -- "$@"
+!mime ^text, label pager,  ext xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@"
+
+ext 1                         = man "$1"
+ext s[wmf]c, has zsnes, X     = zsnes "$1"
+ext s[wmf]c, has snes9x-gtk,X = snes9x-gtk "$1"
+ext nes, has fceux, X         = fceux "$1"
+ext exe                       = wine "$1"
+name ^[mM]akefile$            = make
+
+#--------------------------------------------
+# Scripts
+#-------------------------------------------
+ext py  = python -- "$1"
+ext pl  = perl -- "$1"
+ext rb  = ruby -- "$1"
+ext js  = node -- "$1"
+ext sh  = sh -- "$1"
+ext php = php -- "$1"
+
+#--------------------------------------------
+# Audio without X
+#-------------------------------------------
+mime ^audio|ogg$, terminal, has mpv      = mpv -- "$@"
+mime ^audio|ogg$, terminal, has mplayer2 = mplayer2 -- "$@"
+mime ^audio|ogg$, terminal, has mplayer  = mplayer -- "$@"
+ext midi?,        terminal, has wildmidi = wildmidi -- "$@"
+
+#--------------------------------------------
+# Video/Audio with a GUI
+#-------------------------------------------
+mime ^video|audio, has gmplayer, X, flag f = gmplayer -- "$@"
+mime ^video|audio, has smplayer, X, flag f = smplayer "$@"
+mime ^video,       has mpv,      X, flag f = mpv -- "$@"
+mime ^video,       has mpv,      X, flag f = mpv --fs -- "$@"
+mime ^video,       has mplayer2, X, flag f = mplayer2 -- "$@"
+mime ^video,       has mplayer2, X, flag f = mplayer2 -fs -- "$@"
+mime ^video,       has mplayer,  X, flag f = mplayer -- "$@"
+mime ^video,       has mplayer,  X, flag f = mplayer -fs -- "$@"
+mime ^video|audio, has vlc,      X, flag f = vlc -- "$@"
+mime ^video|audio, has totem,    X, flag f = totem -- "$@"
+mime ^video|audio, has totem,    X, flag f = totem --fullscreen -- "$@"
+
+#--------------------------------------------
+# Video without X
+#-------------------------------------------
+mime ^video, terminal, !X, has mpv       = mpv -- "$@"
+mime ^video, terminal, !X, has mplayer2  = mplayer2 -- "$@"
+mime ^video, terminal, !X, has mplayer   = mplayer -- "$@"
+
+#-------------------------------------------
+# Documents
+#-------------------------------------------
+ext xopp, has xournalpp, X, flag f = devour xournalpp "$@"
+ext drawio, has drawio-desktop, X, flag f = devour draw.io "$@"
+
+ext pdf, has mupdf,    X, flag f = mupdf "$@"
+ext pdf, has llpp,     X, flag f = llpp "$@"
+ext pdf, has zathura,  X, flag f = zathura -- "$@"
+ext pdf, has mupdf-x11,X, flag f = mupdf-x11 "$@"
+ext pdf, has apvlv,    X, flag f = apvlv -- "$@"
+ext pdf, has xpdf,     X, flag f = xpdf -- "$@"
+ext pdf, has evince,   X, flag f = evince -- "$@"
+ext pdf, has atril,    X, flag f = atril -- "$@"
+ext pdf, has okular,   X, flag f = okular -- "$@"
+ext pdf, has epdfview, X, flag f = epdfview -- "$@"
+ext pdf, has qpdfview, X, flag f = qpdfview "$@"
+ext pdf, has open,     X, flag f = open "$@"
+
+ext docx?, has catdoc,       terminal = catdoc -- "$@" | "$PAGER"
+
+ext                        sxc|xlsx?|xlt|xlw|gnm|gnumeric, has gnumeric,    X, flag f = gnumeric -- "$@"
+ext                        sxc|xlsx?|xlt|xlw|gnm|gnumeric, has kspread,     X, flag f = kspread -- "$@"
+ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has libreoffice, X, flag f = libreoffice "$@"
+ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has soffice,     X, flag f = soffice "$@"
+ext pptx?|od[dfgpst]|docx?|sxc|xlsx?|xlt|xlw|gnm|gnumeric, has ooffice,     X, flag f = ooffice "$@"
+
+ext djvu, has zathura,X, flag f = zathura -- "$@"
+ext djvu, has evince, X, flag f = evince -- "$@"
+ext djvu, has atril,  X, flag f = atril -- "$@"
+ext djvu, has djview, X, flag f = djview -- "$@"
+
+ext epub, has ebook-viewer, X, flag f = ebook-viewer -- "$@"
+ext epub, has zathura,      X, flag f = zathura -- "$@"
+ext epub, has mupdf,        X, flag f = mupdf -- "$@"
+ext mobi, has ebook-viewer, X, flag f = ebook-viewer -- "$@"
+
+ext cbr,  has zathura,      X, flag f = zathura -- "$@"
+ext cbz,  has zathura,      X, flag f = zathura -- "$@"
+
+#-------------------------------------------
+# Images
+#-------------------------------------------
+mime ^image/svg, has inkscape, X, flag f = inkscape -- "$@"
+mime ^image/svg, has display,  X, flag f = display -- "$@"
+
+mime ^image, has imv,       X, flag f = imv -- "$@"
+mime ^image, has pqiv,      X, flag f = pqiv -- "$@"
+mime ^image, has sxiv,      X, flag f = sxiv -- "$@"
+mime ^image, has feh,       X, flag f = feh -- "$@"
+mime ^image, has mirage,    X, flag f = mirage -- "$@"
+mime ^image, has ristretto, X, flag f = ristretto "$@"
+mime ^image, has eog,       X, flag f = eog -- "$@"
+mime ^image, has eom,       X, flag f = eom -- "$@"
+mime ^image, has nomacs,    X, flag f = nomacs -- "$@"
+mime ^image, has geeqie,    X, flag f = geeqie -- "$@"
+mime ^image, has gpicview,  X, flag f = gpicview -- "$@"
+mime ^image, has gwenview,  X, flag f = gwenview -- "$@"
+mime ^image, has gimp,      X, flag f = gimp -- "$@"
+ext xcf,                    X, flag f = gimp -- "$@"
+
+#-------------------------------------------
+# Archives
+#-------------------------------------------
+
+# avoid password prompt by providing empty password
+ext 7z, has 7z = 7z -p l "$@" | "$PAGER"
+# This requires atool
+ext ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz,     has atool = atool --list --each -- "$@" | "$PAGER"
+ext iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has atool = atool --list --each -- "$@" | "$PAGER"
+ext 7z|ace|ar|arc|bz2?|cab|cpio|cpt|deb|dgc|dmg|gz,  has atool = atool --extract --each -- "$@"
+ext iso|jar|msi|pkg|rar|shar|tar|tgz|xar|xpi|xz|zip, has atool = atool --extract --each -- "$@"
+
+# Listing and extracting archives without atool:
+ext tar|gz|bz2|xz, has tar = tar vvtf "$1" | "$PAGER"
+ext tar|gz|bz2|xz, has tar = for file in "$@"; do tar vvxf "$file"; done
+ext bz2, has bzip2 = for file in "$@"; do bzip2 -dk "$file"; done
+ext zip, has unzip = unzip -l "$1" | less
+ext zip, has unzip = for file in "$@"; do unzip -d "${file%.*}" "$file"; done
+ext ace, has unace = unace l "$1" | less
+ext ace, has unace = for file in "$@"; do unace e "$file"; done
+ext rar, has unrar = unrar l "$1" | less
+ext rar, has unrar = for file in "$@"; do unrar x "$file"; done
+
+#-------------------------------------------
+# Fonts
+#-------------------------------------------
+mime ^font, has fontforge, X, flag f = fontforge "$@"
+
+#-------------------------------------------
+# Flag t fallback terminals
+#-------------------------------------------
+# Rarely installed terminal emulators get higher priority; It is assumed that
+# if you install a rare terminal emulator, you probably use it.
+# gnome-terminal/konsole/xterm on the other hand are often installed as part of
+# a desktop environment or as fallback terminal emulators.
+mime ^ranger/x-terminal-emulator, has terminology = terminology -e "$@"
+mime ^ranger/x-terminal-emulator, has kitty = kitty -- "$@"
+mime ^ranger/x-terminal-emulator, has alacritty = alacritty -e "$@"
+mime ^ranger/x-terminal-emulator, has sakura = sakura -e "$@"
+mime ^ranger/x-terminal-emulator, has lilyterm = lilyterm -e "$@"
+#mime ^ranger/x-terminal-emulator, has cool-retro-term = cool-retro-term -e "$@"
+mime ^ranger/x-terminal-emulator, has termite = termite -x '"$@"'
+#mime ^ranger/x-terminal-emulator, has yakuake = yakuake -e "$@"
+mime ^ranger/x-terminal-emulator, has guake = guake -ne "$@"
+mime ^ranger/x-terminal-emulator, has tilda = tilda -c "$@"
+mime ^ranger/x-terminal-emulator, has st = st -e "$@"
+mime ^ranger/x-terminal-emulator, has terminator = terminator -x "$@"
+mime ^ranger/x-terminal-emulator, has urxvt = urxvt -e "$@"
+mime ^ranger/x-terminal-emulator, has pantheon-terminal = pantheon-terminal -e "$@"
+mime ^ranger/x-terminal-emulator, has lxterminal = lxterminal -e "$@"
+mime ^ranger/x-terminal-emulator, has mate-terminal = mate-terminal -x "$@"
+mime ^ranger/x-terminal-emulator, has xfce4-terminal = xfce4-terminal -x "$@"
+mime ^ranger/x-terminal-emulator, has konsole = konsole -e "$@"
+mime ^ranger/x-terminal-emulator, has gnome-terminal = gnome-terminal -- "$@"
+mime ^ranger/x-terminal-emulator, has xterm = xterm -e "$@"
+
+#-------------------------------------------
+# Misc
+#-------------------------------------------
+label wallpaper, number 11, mime ^image, has feh, X = feh --bg-scale "$1"
+label wallpaper, number 12, mime ^image, has feh, X = feh --bg-tile "$1"
+label wallpaper, number 13, mime ^image, has feh, X = feh --bg-center "$1"
+label wallpaper, number 14, mime ^image, has feh, X = feh --bg-fill "$1"
+
+#-------------------------------------------
+# Generic file openers
+#-------------------------------------------
+label open, has xdg-open = xdg-open -- "$@"
+label open, has open     = open -- "$@"
+
+# Define the editor for non-text files + pager as last action
+              !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = ask
+label editor, !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = ${VISUAL:-$EDITOR} -- "$@"
+label pager,  !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = "$PAGER" -- "$@"
+
+
+######################################################################
+# The actions below are left so low down in this file on purpose, so #
+# they are never triggered accidentally.                             #
+######################################################################
+
+# Execute a file as program/script.
+mime application/x-executable = "$1"
+
+# Move the file to trash using trash-cli.
+label trash, has trash-put = trash-put -- "$@"
+label trash = mkdir -p -- ${XDG_DATA_DIR:-$HOME/.ranger}/ranger-trash; mv -- "$@" ${XDG_DATA_DIR:-$HOME/.ranger}/ranger-trash

+ 16 - 0
dot-config/readline/inputrc

@@ -0,0 +1,16 @@
+set editing-mode vi
+$if mode=vi
+
+set keymap vi-command
+# these are for vi-command mode
+Control-l: clear-screen
+
+set keymap vi-insert
+# these are for vi-insert mode
+Control-l: clear-screen 
+$endif
+
+# different cursor dependig on editing mode
+set show-mode-in-prompt on
+set vi-cmd-mode-string "\1\e[2 q\2"
+set vi-ins-mode-string "\1\e[6 q\2"

BIN
dot-config/redyt/redyt.png


+ 13 - 0
dot-config/redyt/subreddits

@@ -0,0 +1,13 @@
+linuxmemes    | Memes for GNU/Linux people
+linuxmasterrace
+me_irl        | Selfies of the Soul
+pcmr          | Gaming stuff
+mapporn       | High Quality Maps
+memes         | Memes! Memes! Memes! 😂 I 💖 Memes 
+unixporn      | Screenshots of cool Linux rice. 🐧
+dankmemes     | Memes which are hard to understand.
+art           | Cool Artwork 🖌️ by Cool redditors
+wallpapers    | Good wallpapers for my Desktop.
+AbandonedPorn | High quality images of abandoned things and places.
+animepiracy   | Find the best way to get your Linux iso's
+ProgrammerHumor

+ 20 - 0
dot-config/setup/templates/latex/beamer.tex

@@ -0,0 +1,20 @@
+\documentclass[aspectratio=169]{beamer}
+
+% parse most utf-8 correctly
+\usepackage[utf8]{inputenc}
+
+% better graphics
+\usepackage{graphicx}
+
+% beamer settings
+\title{<++>}
+\author{<++>}
+\institute{<++>}
+\usetheme{Copenhagen}
+
+\begin{document}
+\maketitle
+
+<++>
+
+\end{document}

+ 30 - 0
dot-config/setup/templates/latex/flowchart.tex

@@ -0,0 +1,30 @@
+\documentclass{article}
+
+% input and language settings
+\usepackage[utf8]{inputenc}
+\usepackage[ngerman]{babel}
+
+% import tikz librarys
+\usepackage{tikz}
+\usetikzlibrary{shapes,arrows}
+
+\begin{document}
+\pagestyle{empty}
+
+% define block styles
+\tikzstyle{decision} = [diamond, draw, fill=blue!20, 
+    text width=6.5em, text badly centered, node distance=3cm, inner sep=0pt]
+\tikzstyle{block} = [rectangle, draw, fill=blue!20, 
+    text width=6.5em, text centered, rounded corners, minimum height=4em]
+\tikzstyle{line} = [draw, -latex']
+\tikzstyle{cloud} = [draw, ellipse,fill=red!20, node distance=3cm,
+    minimum height=2em]
+    
+\begin{tikzpicture}[node distance = 2cm, auto]
+    % place nodes
+	<++>
+
+    % draw paths
+\end{tikzpicture}
+
+\end{document}

+ 10 - 0
dot-config/setup/templates/latex/nb

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# TeX template for a beamer presentation
+
+# exit if no argument given
+[ -z "$*" ] && echo "Error: Usage: nb [filename]" && exit
+
+cp ~/.config/setup/templates/latex/beamer.tex .
+mv beamer.tex "${1%.*}.tex"
+vim -c :1  "${1%.*}.tex"

+ 10 - 0
dot-config/setup/templates/latex/nf

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# TeX template for a tikz flowchart
+
+# exit if no argument given
+[ -z "$*" ] && echo "Error: Usage: nf [filename]" && exit
+
+cp ~/.config/setup/templates/latex/flowchart.tex .
+mv flowchart.tex "${1%.*}.tex"
+vim -c :1  "${1%.*}.tex"

+ 60 - 0
dot-config/setup/templates/latex/school-template.tex

@@ -0,0 +1,60 @@
+%standard
+\documentclass[a4paper,12pt]{scrartcl}
+\usepackage[utf8]{inputenc}
+\usepackage[ngerman]{babel}
+%\selectlanguage{english}
+
+%font
+\usepackage{tgheros}
+\usepackage{mathptmx}
+% use sans serif font
+% \renewcommand{\familydefault}{\sfdefault}
+
+\usepackage[hyphens]{url}
+\usepackage{hyperref}
+
+%pictures
+\usepackage{graphicx}
+\usepackage{wrapfig}
+
+%tables
+\renewcommand{\arraystretch}{1.4}
+\usepackage{multirow}
+
+%special characters
+\usepackage[official]{eurosym}
+\newcommand\tab[1][1cm]{\hspace*{#1}}
+
+%geometry
+\usepackage{geometry}
+\geometry{ headsep=20pt,
+ headheight=20pt,
+ left=21mm,
+ top=15mm,
+ right=21mm,
+ bottom=15mm,
+ footskip=20pt,
+ includeheadfoot}
+
+%header
+\usepackage{datetime}
+\newdateformat{dmy}{%
+  \THEDAY.~\monthname[\THEMONTH] \THEYEAR}
+\usepackage{fancyhdr}
+\pagestyle{fancy}
+\lhead{Noah J. Vogt}
+\chead{}
+\rhead{\dmy\today}
+\lfoot{}
+\cfoot{Gymnasium Kirschgarten}
+\rfoot{}
+
+%indent
+\renewcommand{\footrulewidth}{.4pt}
+\setlength{\parindent}{0em}
+
+\begin{document}
+
+
+
+\end{document}

+ 10 - 0
dot-config/setup/templates/latex/sl

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# TeX template for use in school
+
+# exit if no argument given
+[ -z "$*" ] && echo "Error: Usage: sl [filename]" && exit
+
+cp ~/.config/setup/templates/latex/school-template.tex .
+mv school-template.tex "${1%.*}.tex"
+nvim -c :58  "${1%.*}.tex"

+ 105 - 0
dot-config/setup/templates/pandoc/dark-website.html

@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
+<head>
+  <meta charset="utf-8" />
+  <meta name="generator" content="pandoc" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+$for(author-meta)$
+  <meta name="author" content="$author-meta$" />
+$endfor$
+$if(date-meta)$
+  <meta name="dcterms.date" content="$date-meta$" />
+$endif$
+$if(keywords)$
+  <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
+$endif$
+$if(description-meta)$
+  <meta name="description" content="$description-meta$" />
+$endif$
+  <title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
+  <style>
+    $styles.html()$
+    html {
+        background-color: #606263;
+        font-size: 20px;
+    }
+    figcaption {
+        text-align: center;
+        color: #5fd700;
+    }
+pre {
+    background: #4B4C4D;
+    padding-left: 25px;
+    padding-right: 25px;
+    margin-top: 0;
+    margin-bottom: 0px;
+}
+code {
+    padding-top: 3px;
+    padding-bottom: 3px;
+    font-weight: normal;
+    padding-left: 7px;
+    padding-right: 7px;
+    background: #4B4C4D;
+    font: monospace;
+    color: #FFFF12;
+}
+a {
+    color: #02c3f8;
+}
+a:visited {
+    color: #02c3f8;
+}
+
+.center {
+    display: block;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+  </style>
+$for(css)$
+  <link rel="stylesheet" href="$css$" />
+$endfor$
+$if(math)$
+  $math$
+$endif$
+  <!--[if lt IE 9]>
+    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
+  <![endif]-->
+$for(header-includes)$
+  $header-includes$
+$endfor$
+</head>
+<body bgcolor="#606362" link="#02c3f8" alink="#017bf5" vlink="#02c3f8">
+$for(include-before)$
+$include-before$
+$endfor$
+$if(title)$
+<header id="title-block-header">
+<h1 class="title">$title$</h1>
+$if(subtitle)$
+<p class="subtitle">$subtitle$</p>
+$endif$
+$for(author)$
+<p class="author">$author$</p>
+$endfor$
+$if(date)$
+<p class="date">$date$</p>
+$endif$
+</header>
+$endif$
+$if(toc)$
+<nav id="$idprefix$TOC" role="doc-toc">
+$if(toc-title)$
+<h2 id="$idprefix$toc-title">$toc-title$</h2>
+$endif$
+$table-of-contents$
+</nav>
+$endif$
+$body$
+$for(include-after)$
+$include-after$
+$endfor$
+</body>
+</html>

+ 551 - 0
dot-config/setup/templates/pandoc/english.latex

@@ -0,0 +1,551 @@
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
+\PassOptionsToPackage{hyphens}{url}
+$if(colorlinks)$
+\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
+$endif$
+$if(dir)$
+$if(latex-dir-rtl)$
+\PassOptionsToPackage{RTLdocument}{bidi}
+$endif$
+$endif$
+$if(CJKmainfont)$
+\PassOptionsToPackage{space}{xeCJK}
+$endif$
+%
+\documentclass[
+$if(fontsize)$
+  $fontsize$,
+$endif$
+$if(lang)$
+  $babel-lang$,
+$endif$
+$if(papersize)$
+  $papersize$paper,
+$endif$
+$if(beamer)$
+  ignorenonframetext,
+$if(handout)$
+  handout,
+$endif$
+$if(aspectratio)$
+  aspectratio=$aspectratio$,
+$endif$
+$endif$
+$for(classoption)$
+  $classoption$$sep$,
+$endfor$
+]{$documentclass$}
+$if(beamer)$
+$if(background-image)$
+\usebackgroundtemplate{%
+  \includegraphics[width=\paperwidth]{$background-image$}%
+}
+$endif$
+\usepackage{pgfpages}
+\setbeamertemplate{caption}[numbered]
+\setbeamertemplate{caption label separator}{: }
+\setbeamercolor{caption name}{fg=normal text.fg}
+\beamertemplatenavigationsymbols$if(navigation)$$navigation$$else$empty$endif$
+$for(beameroption)$
+\setbeameroption{$beameroption$}
+$endfor$
+% Prevent slide breaks in the middle of a paragraph
+\widowpenalties 1 10000
+\raggedbottom
+$if(section-titles)$
+\setbeamertemplate{part page}{
+  \centering
+  \begin{beamercolorbox}[sep=16pt,center]{part title}
+    \usebeamerfont{part title}\insertpart\par
+  \end{beamercolorbox}
+}
+\setbeamertemplate{section page}{
+  \centering
+  \begin{beamercolorbox}[sep=12pt,center]{part title}
+    \usebeamerfont{section title}\insertsection\par
+  \end{beamercolorbox}
+}
+\setbeamertemplate{subsection page}{
+  \centering
+  \begin{beamercolorbox}[sep=8pt,center]{part title}
+    \usebeamerfont{subsection title}\insertsubsection\par
+  \end{beamercolorbox}
+}
+\AtBeginPart{
+  \frame{\partpage}
+}
+\AtBeginSection{
+  \ifbibliography
+  \else
+    \frame{\sectionpage}
+  \fi
+}
+\AtBeginSubsection{
+  \frame{\subsectionpage}
+}
+$endif$
+$endif$
+$if(beamerarticle)$
+\usepackage{beamerarticle} % needs to be loaded first
+$endif$
+\usepackage{amsmath,amssymb}
+$if(fontfamily)$
+\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
+$else$
+\usepackage{lmodern}
+$endif$
+$if(linestretch)$
+\usepackage{setspace}
+$endif$
+\usepackage{ifxetex,ifluatex}
+
+% my additions
+\usepackage{tgheros}
+\usepackage{mathptmx}
+
+% geometry
+\usepackage{geometry}
+\geometry{ 
+    headsep=20pt,
+    headheight=20pt,
+    left=21mm,
+    top=15mm,
+    right=21mm,
+    bottom=15mm,
+    footskip=20pt, 
+}
+
+\usepackage{hyperref}
+\hypersetup{
+    colorlinks=true,
+    linkcolor=blue,
+    filecolor=magenta,
+    urlcolor=cyan,
+}
+
+\usepackage{sectsty}
+\usepackage[english]{babel}
+\selectlanguage{english}
+\allsectionsfont{\sffamily}
+
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
+  \usepackage[utf8]{inputenc}
+  \usepackage{textcomp} % provide euro and other symbols
+\else % if luatex or xetex
+$if(mathspec)$
+  \ifxetex
+    \usepackage{mathspec}
+  \else
+    \usepackage{unicode-math}
+  \fi
+$else$
+  \usepackage{unicode-math}
+$endif$
+  \defaultfontfeatures{Scale=MatchLowercase}
+  \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
+$if(mainfont)$
+  \setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
+$endif$
+$if(sansfont)$
+  \setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$}
+$endif$
+$if(monofont)$
+  \setmonofont[$for(monofontoptions)$$monofontoptions$$sep$,$endfor$]{$monofont$}
+$endif$
+$for(fontfamilies)$
+  \newfontfamily{$fontfamilies.name$}[$for(fontfamilies.options)$$fontfamilies.options$$sep$,$endfor$]{$fontfamilies.font$}
+$endfor$
+$if(mathfont)$
+$if(mathspec)$
+  \ifxetex
+    \setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \else
+    \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \fi
+$else$
+  \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+$endif$
+$endif$
+$if(CJKmainfont)$
+  \ifxetex
+    \usepackage{xeCJK}
+    \setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+$if(luatexjapresetoptions)$
+  \ifluatex
+    \usepackage[$for(luatexjapresetoptions)$$luatexjapresetoptions$$sep$,$endfor$]{luatexja-preset}
+  \fi
+$endif$
+$if(CJKmainfont)$
+  \ifluatex
+    \usepackage[$for(luatexjafontspecoptions)$$luatexjafontspecoptions$$sep$,$endfor$]{luatexja-fontspec}
+    \setmainjfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+\fi
+$if(beamer)$
+$if(theme)$
+\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
+$endif$
+$if(colortheme)$
+\usecolortheme{$colortheme$}
+$endif$
+$if(fonttheme)$
+\usefonttheme{$fonttheme$}
+$endif$
+$if(mainfont)$
+\usefonttheme{serif} % use mainfont rather than sansfont for slide text
+$endif$
+$if(innertheme)$
+\useinnertheme{$innertheme$}
+$endif$
+$if(outertheme)$
+\useoutertheme{$outertheme$}
+$endif$
+$endif$
+% Use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+\IfFileExists{microtype.sty}{% use microtype if available
+  \usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
+  \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+$if(indent)$
+$else$
+\makeatletter
+\@ifundefined{KOMAClassName}{% if non-KOMA class
+  \IfFileExists{parskip.sty}{%
+    \usepackage{parskip}
+  }{% else
+    \setlength{\parindent}{0pt}
+    \setlength{\parskip}{6pt plus 2pt minus 1pt}}
+}{% if KOMA class
+  \KOMAoptions{parskip=half}}
+\makeatother
+$endif$
+$if(verbatim-in-note)$
+\usepackage{fancyvrb}
+$endif$
+\usepackage{xcolor}
+\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
+\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
+\hypersetup{
+$if(title-meta)$
+  pdftitle={$title-meta$},
+$endif$
+$if(author-meta)$
+  pdfauthor={$author-meta$},
+$endif$
+$if(lang)$
+  pdflang={$lang$},
+$endif$
+$if(subject)$
+  pdfsubject={$subject$},
+$endif$
+$if(keywords)$
+  pdfkeywords={$for(keywords)$$keywords$$sep$, $endfor$},
+$endif$
+$if(colorlinks)$
+  colorlinks=true,
+  linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$,
+  filecolor=$if(filecolor)$$filecolor$$else$Maroon$endif$,
+  citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$,
+  urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$,
+$else$
+  hidelinks,
+$endif$
+  pdfcreator={LaTeX via pandoc}}
+\urlstyle{same} % disable monospaced font for URLs
+$if(verbatim-in-note)$
+\VerbatimFootnotes % allow verbatim text in footnotes
+$endif$
+$if(geometry)$
+$if(beamer)$
+\geometry{$for(geometry)$$geometry$$sep$,$endfor$}
+$else$
+\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
+$endif$
+$endif$
+$if(beamer)$
+\newif\ifbibliography
+$endif$
+$if(listings)$
+\usepackage{listings}
+\newcommand{\passthrough}[1]{#1}
+\lstset{defaultdialect=[5.3]Lua}
+\lstset{defaultdialect=[x86masm]Assembler}
+$endif$
+$if(lhs)$
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+$endif$
+$if(highlighting-macros)$
+$highlighting-macros$
+$endif$
+$if(tables)$
+\usepackage{longtable,booktabs,array}
+\usepackage{calc} % for calculating minipage widths
+$if(beamer)$
+\usepackage{caption}
+% Make caption package work with longtable
+\makeatletter
+\def\fnum@table{\tablename~\thetable}
+\makeatother
+$else$
+% Correct order of tables after \paragraph or \subparagraph
+\usepackage{etoolbox}
+\makeatletter
+\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
+\makeatother
+% Allow footnotes in longtable head/foot
+\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
+\makesavenoteenv{longtable}
+$endif$
+$endif$
+$if(graphics)$
+\usepackage{graphicx}
+\makeatletter
+\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
+\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
+\makeatother
+% Scale images if necessary, so that they will not overflow the page
+% margins by default, and it is still possible to overwrite the defaults
+% using explicit options in \includegraphics[width, height, ...]{}
+\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
+% Set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+$endif$
+$if(links-as-notes)$
+% Make links footnotes instead of hotlinks:
+\DeclareRobustCommand{\href}[2]{#2\footnote{\url{#1}}}
+$endif$
+$if(strikeout)$
+\usepackage[normalem]{ulem}
+% Avoid problems with \sout in headers with hyperref
+\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
+$endif$
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+$if(numbersections)$
+\setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
+$else$
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+$endif$
+$if(beamer)$
+$else$
+$if(block-headings)$
+% Make \paragraph and \subparagraph free-standing
+\ifx\paragraph\undefined\else
+  \let\oldparagraph\paragraph
+  \renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+  \let\oldsubparagraph\subparagraph
+  \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+$endif$
+$endif$
+$if(pagestyle)$
+\pagestyle{$pagestyle$}
+$endif$
+$for(header-includes)$
+$header-includes$
+$endfor$
+$if(lang)$
+\ifxetex
+  % Load polyglossia as late as possible: uses bidi with RTL langages (e.g. Hebrew, Arabic)
+  \usepackage{polyglossia}
+  \setmainlanguage[$for(polyglossia-lang.options)$$polyglossia-lang.options$$sep$,$endfor$]{$polyglossia-lang.name$}
+$for(polyglossia-otherlangs)$
+  \setotherlanguage[$for(polyglossia-otherlangs.options)$$polyglossia-otherlangs.options$$sep$,$endfor$]{$polyglossia-otherlangs.name$}
+$endfor$
+\else
+  \usepackage[$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
+% get rid of language-specific shorthands (see #6817):
+\let\LanguageShortHands\languageshorthands
+\def\languageshorthands#1{}
+$if(babel-newcommands)$
+  $babel-newcommands$
+$endif$
+\fi
+$endif$
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
+$if(dir)$
+\ifxetex
+  % Load bidi as late as possible as it modifies e.g. graphicx
+  \usepackage{bidi}
+\fi
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \TeXXeTstate=1
+  \newcommand{\RL}[1]{\beginR #1\endR}
+  \newcommand{\LR}[1]{\beginL #1\endL}
+  \newenvironment{RTL}{\beginR}{\endR}
+  \newenvironment{LTR}{\beginL}{\endL}
+\fi
+$endif$
+$if(natbib)$
+\usepackage[$natbiboptions$]{natbib}
+\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
+$endif$
+$if(biblatex)$
+\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
+$for(bibliography)$
+\addbibresource{$bibliography$}
+$endfor$
+$endif$
+$if(csl-refs)$
+\newlength{\cslhangindent}
+\setlength{\cslhangindent}{1.5em}
+\newlength{\csllabelwidth}
+\setlength{\csllabelwidth}{3em}
+\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
+ {% don't indent paragraphs
+  \setlength{\parindent}{0pt}
+  % turn on hanging indent if param 1 is 1
+  \ifodd #1 \everypar{\setlength{\hangindent}{\cslhangindent}}\ignorespaces\fi
+  % set entry spacing
+  \ifnum #2 > 0
+  \setlength{\parskip}{#2\baselineskip}
+  \fi
+ }%
+ {}
+\usepackage{calc}
+\newcommand{\CSLBlock}[1]{#1\hfill\break}
+\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
+\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
+\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
+$endif$
+$if(csquotes)$
+\usepackage{csquotes}
+$endif$
+
+$if(title)$
+\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
+$endif$
+$if(subtitle)$
+$if(beamer)$
+$else$
+\usepackage{etoolbox}
+\makeatletter
+\providecommand{\subtitle}[1]{% add subtitle to \maketitle
+  \apptocmd{\@title}{\par {\large #1 \par}}{}{}
+}
+\makeatother
+$endif$
+\subtitle{$subtitle$}
+$endif$
+\author{$for(author)$$author$$sep$ \and $endfor$}
+\date{$date$}
+$if(beamer)$
+$if(institute)$
+\institute{$for(institute)$$institute$$sep$ \and $endfor$}
+$endif$
+$if(titlegraphic)$
+\titlegraphic{\includegraphics{$titlegraphic$}}
+$endif$
+$if(logo)$
+\logo{\includegraphics{$logo$}}
+$endif$
+$endif$
+
+\begin{document}
+$if(has-frontmatter)$
+\frontmatter
+$endif$
+$if(title)$
+$if(beamer)$
+\frame{\titlepage}
+$else$
+\maketitle
+$endif$
+$if(abstract)$
+\begin{abstract}
+$abstract$
+\end{abstract}
+$endif$
+$endif$
+
+$for(include-before)$
+$include-before$
+
+$endfor$
+$if(toc)$
+$if(toc-title)$
+\renewcommand*\contentsname{$toc-title$}
+$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]
+$if(toc-title)$
+  \frametitle{$toc-title$}
+$endif$
+  \tableofcontents[hideallsubsections]
+\end{frame}
+$else$
+{
+$if(colorlinks)$
+\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$$endif$}
+$endif$
+\setcounter{tocdepth}{$toc-depth$}
+\tableofcontents
+}
+$endif$
+$endif$
+$if(lot)$
+\listoftables
+$endif$
+$if(lof)$
+\listoffigures
+$endif$
+$if(linestretch)$
+\setstretch{$linestretch$}
+$endif$
+$if(has-frontmatter)$
+\mainmatter
+$endif$
+$body$
+
+$if(has-frontmatter)$
+\backmatter
+$endif$
+$if(natbib)$
+$if(bibliography)$
+$if(biblio-title)$
+$if(has-chapters)$
+\renewcommand\bibname{$biblio-title$}
+$else$
+\renewcommand\refname{$biblio-title$}
+$endif$
+$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+  \bibliographytrue
+$endif$
+  \bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
+$if(beamer)$
+\end{frame}
+$endif$
+
+$endif$
+$endif$
+$if(biblatex)$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+  \bibliographytrue
+  \printbibliography[heading=none]
+\end{frame}
+$else$
+\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
+$endif$
+
+$endif$
+$for(include-after)$
+$include-after$
+
+$endfor$
+\end{document}

+ 551 - 0
dot-config/setup/templates/pandoc/french.latex

@@ -0,0 +1,551 @@
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
+\PassOptionsToPackage{hyphens}{url}
+$if(colorlinks)$
+\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
+$endif$
+$if(dir)$
+$if(latex-dir-rtl)$
+\PassOptionsToPackage{RTLdocument}{bidi}
+$endif$
+$endif$
+$if(CJKmainfont)$
+\PassOptionsToPackage{space}{xeCJK}
+$endif$
+%
+\documentclass[
+$if(fontsize)$
+  $fontsize$,
+$endif$
+$if(lang)$
+  $babel-lang$,
+$endif$
+$if(papersize)$
+  $papersize$paper,
+$endif$
+$if(beamer)$
+  ignorenonframetext,
+$if(handout)$
+  handout,
+$endif$
+$if(aspectratio)$
+  aspectratio=$aspectratio$,
+$endif$
+$endif$
+$for(classoption)$
+  $classoption$$sep$,
+$endfor$
+]{$documentclass$}
+$if(beamer)$
+$if(background-image)$
+\usebackgroundtemplate{%
+  \includegraphics[width=\paperwidth]{$background-image$}%
+}
+$endif$
+\usepackage{pgfpages}
+\setbeamertemplate{caption}[numbered]
+\setbeamertemplate{caption label separator}{: }
+\setbeamercolor{caption name}{fg=normal text.fg}
+\beamertemplatenavigationsymbols$if(navigation)$$navigation$$else$empty$endif$
+$for(beameroption)$
+\setbeameroption{$beameroption$}
+$endfor$
+% Prevent slide breaks in the middle of a paragraph
+\widowpenalties 1 10000
+\raggedbottom
+$if(section-titles)$
+\setbeamertemplate{part page}{
+  \centering
+  \begin{beamercolorbox}[sep=16pt,center]{part title}
+    \usebeamerfont{part title}\insertpart\par
+  \end{beamercolorbox}
+}
+\setbeamertemplate{section page}{
+  \centering
+  \begin{beamercolorbox}[sep=12pt,center]{part title}
+    \usebeamerfont{section title}\insertsection\par
+  \end{beamercolorbox}
+}
+\setbeamertemplate{subsection page}{
+  \centering
+  \begin{beamercolorbox}[sep=8pt,center]{part title}
+    \usebeamerfont{subsection title}\insertsubsection\par
+  \end{beamercolorbox}
+}
+\AtBeginPart{
+  \frame{\partpage}
+}
+\AtBeginSection{
+  \ifbibliography
+  \else
+    \frame{\sectionpage}
+  \fi
+}
+\AtBeginSubsection{
+  \frame{\subsectionpage}
+}
+$endif$
+$endif$
+$if(beamerarticle)$
+\usepackage{beamerarticle} % needs to be loaded first
+$endif$
+\usepackage{amsmath,amssymb}
+$if(fontfamily)$
+\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
+$else$
+\usepackage{lmodern}
+$endif$
+$if(linestretch)$
+\usepackage{setspace}
+$endif$
+\usepackage{ifxetex,ifluatex}
+
+% my additions
+\usepackage{tgheros}
+\usepackage{mathptmx}
+
+% geometry
+\usepackage{geometry}
+\geometry{ 
+    headsep=20pt,
+    headheight=20pt,
+    left=21mm,
+    top=15mm,
+    right=21mm,
+    bottom=15mm,
+    footskip=20pt, 
+}
+
+\usepackage{hyperref}
+\hypersetup{
+    colorlinks=true,
+    linkcolor=blue,
+    filecolor=magenta,
+    urlcolor=cyan,
+}
+
+\usepackage{sectsty}
+\usepackage[english]{babel}
+\selectlanguage{french}
+\allsectionsfont{\sffamily}
+
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
+  \usepackage[utf8]{inputenc}
+  \usepackage{textcomp} % provide euro and other symbols
+\else % if luatex or xetex
+$if(mathspec)$
+  \ifxetex
+    \usepackage{mathspec}
+  \else
+    \usepackage{unicode-math}
+  \fi
+$else$
+  \usepackage{unicode-math}
+$endif$
+  \defaultfontfeatures{Scale=MatchLowercase}
+  \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
+$if(mainfont)$
+  \setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
+$endif$
+$if(sansfont)$
+  \setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$}
+$endif$
+$if(monofont)$
+  \setmonofont[$for(monofontoptions)$$monofontoptions$$sep$,$endfor$]{$monofont$}
+$endif$
+$for(fontfamilies)$
+  \newfontfamily{$fontfamilies.name$}[$for(fontfamilies.options)$$fontfamilies.options$$sep$,$endfor$]{$fontfamilies.font$}
+$endfor$
+$if(mathfont)$
+$if(mathspec)$
+  \ifxetex
+    \setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \else
+    \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \fi
+$else$
+  \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+$endif$
+$endif$
+$if(CJKmainfont)$
+  \ifxetex
+    \usepackage{xeCJK}
+    \setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+$if(luatexjapresetoptions)$
+  \ifluatex
+    \usepackage[$for(luatexjapresetoptions)$$luatexjapresetoptions$$sep$,$endfor$]{luatexja-preset}
+  \fi
+$endif$
+$if(CJKmainfont)$
+  \ifluatex
+    \usepackage[$for(luatexjafontspecoptions)$$luatexjafontspecoptions$$sep$,$endfor$]{luatexja-fontspec}
+    \setmainjfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+\fi
+$if(beamer)$
+$if(theme)$
+\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
+$endif$
+$if(colortheme)$
+\usecolortheme{$colortheme$}
+$endif$
+$if(fonttheme)$
+\usefonttheme{$fonttheme$}
+$endif$
+$if(mainfont)$
+\usefonttheme{serif} % use mainfont rather than sansfont for slide text
+$endif$
+$if(innertheme)$
+\useinnertheme{$innertheme$}
+$endif$
+$if(outertheme)$
+\useoutertheme{$outertheme$}
+$endif$
+$endif$
+% Use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+\IfFileExists{microtype.sty}{% use microtype if available
+  \usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
+  \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+$if(indent)$
+$else$
+\makeatletter
+\@ifundefined{KOMAClassName}{% if non-KOMA class
+  \IfFileExists{parskip.sty}{%
+    \usepackage{parskip}
+  }{% else
+    \setlength{\parindent}{0pt}
+    \setlength{\parskip}{6pt plus 2pt minus 1pt}}
+}{% if KOMA class
+  \KOMAoptions{parskip=half}}
+\makeatother
+$endif$
+$if(verbatim-in-note)$
+\usepackage{fancyvrb}
+$endif$
+\usepackage{xcolor}
+\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
+\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
+\hypersetup{
+$if(title-meta)$
+  pdftitle={$title-meta$},
+$endif$
+$if(author-meta)$
+  pdfauthor={$author-meta$},
+$endif$
+$if(lang)$
+  pdflang={$lang$},
+$endif$
+$if(subject)$
+  pdfsubject={$subject$},
+$endif$
+$if(keywords)$
+  pdfkeywords={$for(keywords)$$keywords$$sep$, $endfor$},
+$endif$
+$if(colorlinks)$
+  colorlinks=true,
+  linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$,
+  filecolor=$if(filecolor)$$filecolor$$else$Maroon$endif$,
+  citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$,
+  urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$,
+$else$
+  hidelinks,
+$endif$
+  pdfcreator={LaTeX via pandoc}}
+\urlstyle{same} % disable monospaced font for URLs
+$if(verbatim-in-note)$
+\VerbatimFootnotes % allow verbatim text in footnotes
+$endif$
+$if(geometry)$
+$if(beamer)$
+\geometry{$for(geometry)$$geometry$$sep$,$endfor$}
+$else$
+\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
+$endif$
+$endif$
+$if(beamer)$
+\newif\ifbibliography
+$endif$
+$if(listings)$
+\usepackage{listings}
+\newcommand{\passthrough}[1]{#1}
+\lstset{defaultdialect=[5.3]Lua}
+\lstset{defaultdialect=[x86masm]Assembler}
+$endif$
+$if(lhs)$
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+$endif$
+$if(highlighting-macros)$
+$highlighting-macros$
+$endif$
+$if(tables)$
+\usepackage{longtable,booktabs,array}
+\usepackage{calc} % for calculating minipage widths
+$if(beamer)$
+\usepackage{caption}
+% Make caption package work with longtable
+\makeatletter
+\def\fnum@table{\tablename~\thetable}
+\makeatother
+$else$
+% Correct order of tables after \paragraph or \subparagraph
+\usepackage{etoolbox}
+\makeatletter
+\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
+\makeatother
+% Allow footnotes in longtable head/foot
+\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
+\makesavenoteenv{longtable}
+$endif$
+$endif$
+$if(graphics)$
+\usepackage{graphicx}
+\makeatletter
+\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
+\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
+\makeatother
+% Scale images if necessary, so that they will not overflow the page
+% margins by default, and it is still possible to overwrite the defaults
+% using explicit options in \includegraphics[width, height, ...]{}
+\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
+% Set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+$endif$
+$if(links-as-notes)$
+% Make links footnotes instead of hotlinks:
+\DeclareRobustCommand{\href}[2]{#2\footnote{\url{#1}}}
+$endif$
+$if(strikeout)$
+\usepackage[normalem]{ulem}
+% Avoid problems with \sout in headers with hyperref
+\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
+$endif$
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+$if(numbersections)$
+\setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
+$else$
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+$endif$
+$if(beamer)$
+$else$
+$if(block-headings)$
+% Make \paragraph and \subparagraph free-standing
+\ifx\paragraph\undefined\else
+  \let\oldparagraph\paragraph
+  \renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+  \let\oldsubparagraph\subparagraph
+  \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+$endif$
+$endif$
+$if(pagestyle)$
+\pagestyle{$pagestyle$}
+$endif$
+$for(header-includes)$
+$header-includes$
+$endfor$
+$if(lang)$
+\ifxetex
+  % Load polyglossia as late as possible: uses bidi with RTL langages (e.g. Hebrew, Arabic)
+  \usepackage{polyglossia}
+  \setmainlanguage[$for(polyglossia-lang.options)$$polyglossia-lang.options$$sep$,$endfor$]{$polyglossia-lang.name$}
+$for(polyglossia-otherlangs)$
+  \setotherlanguage[$for(polyglossia-otherlangs.options)$$polyglossia-otherlangs.options$$sep$,$endfor$]{$polyglossia-otherlangs.name$}
+$endfor$
+\else
+  \usepackage[$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
+% get rid of language-specific shorthands (see #6817):
+\let\LanguageShortHands\languageshorthands
+\def\languageshorthands#1{}
+$if(babel-newcommands)$
+  $babel-newcommands$
+$endif$
+\fi
+$endif$
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
+$if(dir)$
+\ifxetex
+  % Load bidi as late as possible as it modifies e.g. graphicx
+  \usepackage{bidi}
+\fi
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \TeXXeTstate=1
+  \newcommand{\RL}[1]{\beginR #1\endR}
+  \newcommand{\LR}[1]{\beginL #1\endL}
+  \newenvironment{RTL}{\beginR}{\endR}
+  \newenvironment{LTR}{\beginL}{\endL}
+\fi
+$endif$
+$if(natbib)$
+\usepackage[$natbiboptions$]{natbib}
+\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
+$endif$
+$if(biblatex)$
+\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
+$for(bibliography)$
+\addbibresource{$bibliography$}
+$endfor$
+$endif$
+$if(csl-refs)$
+\newlength{\cslhangindent}
+\setlength{\cslhangindent}{1.5em}
+\newlength{\csllabelwidth}
+\setlength{\csllabelwidth}{3em}
+\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
+ {% don't indent paragraphs
+  \setlength{\parindent}{0pt}
+  % turn on hanging indent if param 1 is 1
+  \ifodd #1 \everypar{\setlength{\hangindent}{\cslhangindent}}\ignorespaces\fi
+  % set entry spacing
+  \ifnum #2 > 0
+  \setlength{\parskip}{#2\baselineskip}
+  \fi
+ }%
+ {}
+\usepackage{calc}
+\newcommand{\CSLBlock}[1]{#1\hfill\break}
+\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
+\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
+\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
+$endif$
+$if(csquotes)$
+\usepackage{csquotes}
+$endif$
+
+$if(title)$
+\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
+$endif$
+$if(subtitle)$
+$if(beamer)$
+$else$
+\usepackage{etoolbox}
+\makeatletter
+\providecommand{\subtitle}[1]{% add subtitle to \maketitle
+  \apptocmd{\@title}{\par {\large #1 \par}}{}{}
+}
+\makeatother
+$endif$
+\subtitle{$subtitle$}
+$endif$
+\author{$for(author)$$author$$sep$ \and $endfor$}
+\date{$date$}
+$if(beamer)$
+$if(institute)$
+\institute{$for(institute)$$institute$$sep$ \and $endfor$}
+$endif$
+$if(titlegraphic)$
+\titlegraphic{\includegraphics{$titlegraphic$}}
+$endif$
+$if(logo)$
+\logo{\includegraphics{$logo$}}
+$endif$
+$endif$
+
+\begin{document}
+$if(has-frontmatter)$
+\frontmatter
+$endif$
+$if(title)$
+$if(beamer)$
+\frame{\titlepage}
+$else$
+\maketitle
+$endif$
+$if(abstract)$
+\begin{abstract}
+$abstract$
+\end{abstract}
+$endif$
+$endif$
+
+$for(include-before)$
+$include-before$
+
+$endfor$
+$if(toc)$
+$if(toc-title)$
+\renewcommand*\contentsname{$toc-title$}
+$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]
+$if(toc-title)$
+  \frametitle{$toc-title$}
+$endif$
+  \tableofcontents[hideallsubsections]
+\end{frame}
+$else$
+{
+$if(colorlinks)$
+\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$$endif$}
+$endif$
+\setcounter{tocdepth}{$toc-depth$}
+\tableofcontents
+}
+$endif$
+$endif$
+$if(lot)$
+\listoftables
+$endif$
+$if(lof)$
+\listoffigures
+$endif$
+$if(linestretch)$
+\setstretch{$linestretch$}
+$endif$
+$if(has-frontmatter)$
+\mainmatter
+$endif$
+$body$
+
+$if(has-frontmatter)$
+\backmatter
+$endif$
+$if(natbib)$
+$if(bibliography)$
+$if(biblio-title)$
+$if(has-chapters)$
+\renewcommand\bibname{$biblio-title$}
+$else$
+\renewcommand\refname{$biblio-title$}
+$endif$
+$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+  \bibliographytrue
+$endif$
+  \bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
+$if(beamer)$
+\end{frame}
+$endif$
+
+$endif$
+$endif$
+$if(biblatex)$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+  \bibliographytrue
+  \printbibliography[heading=none]
+\end{frame}
+$else$
+\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
+$endif$
+
+$endif$
+$for(include-after)$
+$include-after$
+
+$endfor$
+\end{document}

+ 527 - 0
dot-config/setup/templates/pandoc/german-draft.latex

@@ -0,0 +1,527 @@
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
+\PassOptionsToPackage{hyphens}{url}
+$if(colorlinks)$
+\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
+$endif$
+$if(dir)$
+$if(latex-dir-rtl)$
+\PassOptionsToPackage{RTLdocument}{bidi}
+$endif$
+$endif$
+$if(CJKmainfont)$
+\PassOptionsToPackage{space}{xeCJK}
+$endif$
+%
+\documentclass[
+$if(fontsize)$
+  $fontsize$,
+$endif$
+$if(lang)$
+  $babel-lang$,
+$endif$
+$if(papersize)$
+  $papersize$paper,
+$endif$
+$if(beamer)$
+  ignorenonframetext,
+$if(handout)$
+  handout,
+$endif$
+$if(aspectratio)$
+  aspectratio=$aspectratio$,
+$endif$
+$endif$
+$for(classoption)$
+  $classoption$$sep$,
+$endfor$
+draft
+]{$documentclass$}
+$if(beamer)$
+$if(background-image)$
+\usebackgroundtemplate{%
+  \includegraphics[width=\paperwidth]{$background-image$}%
+}
+$endif$
+\usepackage{pgfpages}
+\setbeamertemplate{caption}[numbered]
+\setbeamertemplate{caption label separator}{: }
+\setbeamercolor{caption name}{fg=normal text.fg}
+\beamertemplatenavigationsymbols$if(navigation)$$navigation$$else$empty$endif$
+$for(beameroption)$
+\setbeameroption{$beameroption$}
+$endfor$
+% Prevent slide breaks in the middle of a paragraph
+\widowpenalties 1 10000
+\raggedbottom
+$if(section-titles)$
+\setbeamertemplate{part page}{
+  \centering
+  \begin{beamercolorbox}[sep=16pt,center]{part title}
+    \usebeamerfont{part title}\insertpart\par
+  \end{beamercolorbox}
+}
+\setbeamertemplate{section page}{
+  \centering
+  \begin{beamercolorbox}[sep=12pt,center]{part title}
+    \usebeamerfont{section title}\insertsection\par
+  \end{beamercolorbox}
+}
+\setbeamertemplate{subsection page}{
+  \centering
+  \begin{beamercolorbox}[sep=8pt,center]{part title}
+    \usebeamerfont{subsection title}\insertsubsection\par
+  \end{beamercolorbox}
+}
+\AtBeginPart{
+  \frame{\partpage}
+}
+\AtBeginSection{
+  \ifbibliography
+  \else
+    \frame{\sectionpage}
+  \fi
+}
+\AtBeginSubsection{
+  \frame{\subsectionpage}
+}
+$endif$
+$endif$
+$if(beamerarticle)$
+\usepackage{beamerarticle} % needs to be loaded first
+$endif$
+\usepackage{amsmath,amssymb}
+$if(fontfamily)$
+\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
+$else$
+\usepackage{lmodern}
+$endif$
+$if(linestretch)$
+\usepackage{setspace}
+$endif$
+\usepackage{ifxetex,ifluatex}
+\usepackage{tgheros}
+\usepackage{mathptmx}
+\usepackage{sectsty}
+\usepackage[ngerman]{babel}
+\allsectionsfont{\sffamily}
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
+  \usepackage[utf8]{inputenc}
+  \usepackage{textcomp} % provide euro and other symbols
+\else % if luatex or xetex
+$if(mathspec)$
+  \ifxetex
+    \usepackage{mathspec}
+  \else
+    \usepackage{unicode-math}
+  \fi
+$else$
+  \usepackage{unicode-math}
+$endif$
+  \defaultfontfeatures{Scale=MatchLowercase}
+  \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
+$if(mainfont)$
+  \setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
+$endif$
+$if(sansfont)$
+  \setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$}
+$endif$
+$if(monofont)$
+  \setmonofont[$for(monofontoptions)$$monofontoptions$$sep$,$endfor$]{$monofont$}
+$endif$
+$for(fontfamilies)$
+  \newfontfamily{$fontfamilies.name$}[$for(fontfamilies.options)$$fontfamilies.options$$sep$,$endfor$]{$fontfamilies.font$}
+$endfor$
+$if(mathfont)$
+$if(mathspec)$
+  \ifxetex
+    \setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \else
+    \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \fi
+$else$
+  \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+$endif$
+$endif$
+$if(CJKmainfont)$
+  \ifxetex
+    \usepackage{xeCJK}
+    \setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+$if(luatexjapresetoptions)$
+  \ifluatex
+    \usepackage[$for(luatexjapresetoptions)$$luatexjapresetoptions$$sep$,$endfor$]{luatexja-preset}
+  \fi
+$endif$
+$if(CJKmainfont)$
+  \ifluatex
+    \usepackage[$for(luatexjafontspecoptions)$$luatexjafontspecoptions$$sep$,$endfor$]{luatexja-fontspec}
+    \setmainjfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+\fi
+$if(beamer)$
+$if(theme)$
+\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
+$endif$
+$if(colortheme)$
+\usecolortheme{$colortheme$}
+$endif$
+$if(fonttheme)$
+\usefonttheme{$fonttheme$}
+$endif$
+$if(mainfont)$
+\usefonttheme{serif} % use mainfont rather than sansfont for slide text
+$endif$
+$if(innertheme)$
+\useinnertheme{$innertheme$}
+$endif$
+$if(outertheme)$
+\useoutertheme{$outertheme$}
+$endif$
+$endif$
+% Use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+\IfFileExists{microtype.sty}{% use microtype if available
+  \usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
+  \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+$if(indent)$
+$else$
+\makeatletter
+\@ifundefined{KOMAClassName}{% if non-KOMA class
+  \IfFileExists{parskip.sty}{%
+    \usepackage{parskip}
+  }{% else
+    \setlength{\parindent}{0pt}
+    \setlength{\parskip}{6pt plus 2pt minus 1pt}}
+}{% if KOMA class
+  \KOMAoptions{parskip=half}}
+\makeatother
+$endif$
+$if(verbatim-in-note)$
+\usepackage{fancyvrb}
+$endif$
+\usepackage{xcolor}
+\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
+\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
+\hypersetup{
+$if(title-meta)$
+  pdftitle={$title-meta$},
+$endif$
+$if(author-meta)$
+  pdfauthor={$author-meta$},
+$endif$
+$if(lang)$
+  pdflang={$lang$},
+$endif$
+$if(subject)$
+  pdfsubject={$subject$},
+$endif$
+$if(keywords)$
+  pdfkeywords={$for(keywords)$$keywords$$sep$, $endfor$},
+$endif$
+$if(colorlinks)$
+  colorlinks=true,
+  linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$,
+  filecolor=$if(filecolor)$$filecolor$$else$Maroon$endif$,
+  citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$,
+  urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$,
+$else$
+  hidelinks,
+$endif$
+  pdfcreator={LaTeX via pandoc}}
+\urlstyle{same} % disable monospaced font for URLs
+$if(verbatim-in-note)$
+\VerbatimFootnotes % allow verbatim text in footnotes
+$endif$
+$if(geometry)$
+$if(beamer)$
+\geometry{$for(geometry)$$geometry$$sep$,$endfor$}
+$else$
+\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
+$endif$
+$endif$
+$if(beamer)$
+\newif\ifbibliography
+$endif$
+$if(listings)$
+\usepackage{listings}
+\newcommand{\passthrough}[1]{#1}
+\lstset{defaultdialect=[5.3]Lua}
+\lstset{defaultdialect=[x86masm]Assembler}
+$endif$
+$if(lhs)$
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+$endif$
+$if(highlighting-macros)$
+$highlighting-macros$
+$endif$
+$if(tables)$
+\usepackage{longtable,booktabs,array}
+\usepackage{calc} % for calculating minipage widths
+$if(beamer)$
+\usepackage{caption}
+% Make caption package work with longtable
+\makeatletter
+\def\fnum@table{\tablename~\thetable}
+\makeatother
+$else$
+% Correct order of tables after \paragraph or \subparagraph
+\usepackage{etoolbox}
+\makeatletter
+\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
+\makeatother
+% Allow footnotes in longtable head/foot
+\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
+\makesavenoteenv{longtable}
+$endif$
+$endif$
+$if(graphics)$
+\usepackage{graphicx}
+\makeatletter
+\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
+\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
+\makeatother
+% Scale images if necessary, so that they will not overflow the page
+% margins by default, and it is still possible to overwrite the defaults
+% using explicit options in \includegraphics[width, height, ...]{}
+\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
+% Set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+$endif$
+$if(links-as-notes)$
+% Make links footnotes instead of hotlinks:
+\DeclareRobustCommand{\href}[2]{#2\footnote{\url{#1}}}
+$endif$
+$if(strikeout)$
+\usepackage[normalem]{ulem}
+% Avoid problems with \sout in headers with hyperref
+\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
+$endif$
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+$if(numbersections)$
+\setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
+$else$
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+$endif$
+$if(beamer)$
+$else$
+$if(block-headings)$
+% Make \paragraph and \subparagraph free-standing
+\ifx\paragraph\undefined\else
+  \let\oldparagraph\paragraph
+  \renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+  \let\oldsubparagraph\subparagraph
+  \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+$endif$
+$endif$
+$if(pagestyle)$
+\pagestyle{$pagestyle$}
+$endif$
+$for(header-includes)$
+$header-includes$
+$endfor$
+$if(lang)$
+\ifxetex
+  % Load polyglossia as late as possible: uses bidi with RTL langages (e.g. Hebrew, Arabic)
+  \usepackage{polyglossia}
+  \setmainlanguage[$for(polyglossia-lang.options)$$polyglossia-lang.options$$sep$,$endfor$]{$polyglossia-lang.name$}
+$for(polyglossia-otherlangs)$
+  \setotherlanguage[$for(polyglossia-otherlangs.options)$$polyglossia-otherlangs.options$$sep$,$endfor$]{$polyglossia-otherlangs.name$}
+$endfor$
+\else
+  \usepackage[$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
+% get rid of language-specific shorthands (see #6817):
+\let\LanguageShortHands\languageshorthands
+\def\languageshorthands#1{}
+$if(babel-newcommands)$
+  $babel-newcommands$
+$endif$
+\fi
+$endif$
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
+$if(dir)$
+\ifxetex
+  % Load bidi as late as possible as it modifies e.g. graphicx
+  \usepackage{bidi}
+\fi
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \TeXXeTstate=1
+  \newcommand{\RL}[1]{\beginR #1\endR}
+  \newcommand{\LR}[1]{\beginL #1\endL}
+  \newenvironment{RTL}{\beginR}{\endR}
+  \newenvironment{LTR}{\beginL}{\endL}
+\fi
+$endif$
+$if(natbib)$
+\usepackage[$natbiboptions$]{natbib}
+\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
+$endif$
+$if(biblatex)$
+\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
+$for(bibliography)$
+\addbibresource{$bibliography$}
+$endfor$
+$endif$
+$if(csl-refs)$
+\newlength{\cslhangindent}
+\setlength{\cslhangindent}{1.5em}
+\newlength{\csllabelwidth}
+\setlength{\csllabelwidth}{3em}
+\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
+ {% don't indent paragraphs
+  \setlength{\parindent}{0pt}
+  % turn on hanging indent if param 1 is 1
+  \ifodd #1 \everypar{\setlength{\hangindent}{\cslhangindent}}\ignorespaces\fi
+  % set entry spacing
+  \ifnum #2 > 0
+  \setlength{\parskip}{#2\baselineskip}
+  \fi
+ }%
+ {}
+\usepackage{calc}
+\newcommand{\CSLBlock}[1]{#1\hfill\break}
+\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
+\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
+\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
+$endif$
+$if(csquotes)$
+\usepackage{csquotes}
+$endif$
+
+$if(title)$
+\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
+$endif$
+$if(subtitle)$
+$if(beamer)$
+$else$
+\usepackage{etoolbox}
+\makeatletter
+\providecommand{\subtitle}[1]{% add subtitle to \maketitle
+  \apptocmd{\@title}{\par {\large #1 \par}}{}{}
+}
+\makeatother
+$endif$
+\subtitle{$subtitle$}
+$endif$
+\author{$for(author)$$author$$sep$ \and $endfor$}
+\date{$date$}
+$if(beamer)$
+$if(institute)$
+\institute{$for(institute)$$institute$$sep$ \and $endfor$}
+$endif$
+$if(titlegraphic)$
+\titlegraphic{\includegraphics{$titlegraphic$}}
+$endif$
+$if(logo)$
+\logo{\includegraphics{$logo$}}
+$endif$
+$endif$
+
+\begin{document}
+$if(has-frontmatter)$
+\frontmatter
+$endif$
+$if(title)$
+$if(beamer)$
+\frame{\titlepage}
+$else$
+\maketitle
+$endif$
+$if(abstract)$
+\begin{abstract}
+$abstract$
+\end{abstract}
+$endif$
+$endif$
+
+$for(include-before)$
+$include-before$
+
+$endfor$
+$if(toc)$
+$if(toc-title)$
+\renewcommand*\contentsname{$toc-title$}
+$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]
+$if(toc-title)$
+  \frametitle{$toc-title$}
+$endif$
+  \tableofcontents[hideallsubsections]
+\end{frame}
+$else$
+{
+$if(colorlinks)$
+\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$$endif$}
+$endif$
+\setcounter{tocdepth}{$toc-depth$}
+\tableofcontents
+}
+$endif$
+$endif$
+$if(lot)$
+\listoftables
+$endif$
+$if(lof)$
+\listoffigures
+$endif$
+$if(linestretch)$
+\setstretch{$linestretch$}
+$endif$
+$if(has-frontmatter)$
+\mainmatter
+$endif$
+$body$
+
+$if(has-frontmatter)$
+\backmatter
+$endif$
+$if(natbib)$
+$if(bibliography)$
+$if(biblio-title)$
+$if(has-chapters)$
+\renewcommand\bibname{$biblio-title$}
+$else$
+\renewcommand\refname{$biblio-title$}
+$endif$
+$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+  \bibliographytrue
+$endif$
+  \bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
+$if(beamer)$
+\end{frame}
+$endif$
+
+$endif$
+$endif$
+$if(biblatex)$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+  \bibliographytrue
+  \printbibliography[heading=none]
+\end{frame}
+$else$
+\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
+$endif$
+
+$endif$
+$for(include-after)$
+$include-after$
+
+$endfor$
+\end{document}

+ 557 - 0
dot-config/setup/templates/pandoc/german.latex

@@ -0,0 +1,557 @@
+% Options for packages loaded elsewhere
+\PassOptionsToPackage{unicode$for(hyperrefoptions)$,$hyperrefoptions$$endfor$}{hyperref}
+\PassOptionsToPackage{hyphens}{url}
+$if(colorlinks)$
+\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
+$endif$
+$if(dir)$
+$if(latex-dir-rtl)$
+\PassOptionsToPackage{RTLdocument}{bidi}
+$endif$
+$endif$
+$if(CJKmainfont)$
+\PassOptionsToPackage{space}{xeCJK}
+$endif$
+%
+\documentclass[
+$if(fontsize)$
+  $fontsize$,
+$endif$
+$if(lang)$
+  $babel-lang$,
+$endif$
+$if(papersize)$
+  $papersize$paper,
+$endif$
+$if(beamer)$
+  ignorenonframetext,
+$if(handout)$
+  handout,
+$endif$
+$if(aspectratio)$
+  aspectratio=$aspectratio$,
+$endif$
+$endif$
+$for(classoption)$
+  $classoption$$sep$,
+$endfor$
+]{$documentclass$}
+$if(beamer)$
+$if(background-image)$
+\usebackgroundtemplate{%
+  \includegraphics[width=\paperwidth]{$background-image$}%
+}
+$endif$
+\usepackage{pgfpages}
+\setbeamertemplate{caption}[numbered]
+\setbeamertemplate{caption label separator}{: }
+\setbeamercolor{caption name}{fg=normal text.fg}
+\beamertemplatenavigationsymbols$if(navigation)$$navigation$$else$empty$endif$
+$for(beameroption)$
+\setbeameroption{$beameroption$}
+$endfor$
+% Prevent slide breaks in the middle of a paragraph
+\widowpenalties 1 10000
+\raggedbottom
+$if(section-titles)$
+\setbeamertemplate{part page}{
+  \centering
+  \begin{beamercolorbox}[sep=16pt,center]{part title}
+    \usebeamerfont{part title}\insertpart\par
+  \end{beamercolorbox}
+}
+\setbeamertemplate{section page}{
+  \centering
+  \begin{beamercolorbox}[sep=12pt,center]{part title}
+    \usebeamerfont{section title}\insertsection\par
+  \end{beamercolorbox}
+}
+\setbeamertemplate{subsection page}{
+  \centering
+  \begin{beamercolorbox}[sep=8pt,center]{part title}
+    \usebeamerfont{subsection title}\insertsubsection\par
+  \end{beamercolorbox}
+}
+\AtBeginPart{
+  \frame{\partpage}
+}
+\AtBeginSection{
+  \ifbibliography
+  \else
+    \frame{\sectionpage}
+  \fi
+}
+\AtBeginSubsection{
+  \frame{\subsectionpage}
+}
+$endif$
+$endif$
+$if(beamerarticle)$
+\usepackage{beamerarticle} % needs to be loaded first
+$endif$
+\usepackage{amsmath,amssymb}
+$if(fontfamily)$
+\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$}
+$else$
+\usepackage{lmodern}
+$endif$
+$if(linestretch)$
+\usepackage{setspace}
+$endif$
+\usepackage{ifxetex,ifluatex}
+
+% my additions
+\usepackage{tgheros}
+\usepackage{mathptmx}
+
+% geometry
+\usepackage{geometry}
+\geometry{ 
+    headsep=20pt,
+    headheight=20pt,
+    left=21mm,
+    top=15mm,
+    right=21mm,
+    bottom=15mm,
+    footskip=20pt, 
+}
+
+\usepackage{hyperref}
+\hypersetup{
+    colorlinks=true,
+    linkcolor=blue,
+    filecolor=magenta,
+    urlcolor=cyan,
+}
+
+\usepackage{sectsty}
+\usepackage[ngerman]{babel}
+\allsectionsfont{\sffamily}
+
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc}
+  \usepackage[utf8]{inputenc}
+  \usepackage{textcomp} % provide euro and other symbols
+\else % if luatex or xetex
+$if(mathspec)$
+  \ifxetex
+    \usepackage{mathspec}
+  \else
+    \usepackage{unicode-math}
+  \fi
+$else$
+  \usepackage{unicode-math}
+$endif$
+  \defaultfontfeatures{Scale=MatchLowercase}
+  \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
+$if(mainfont)$
+  \setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$}
+$endif$
+$if(sansfont)$
+  \setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$}
+$endif$
+$if(monofont)$
+  \setmonofont[$for(monofontoptions)$$monofontoptions$$sep$,$endfor$]{$monofont$}
+$endif$
+$for(fontfamilies)$
+  \newfontfamily{$fontfamilies.name$}[$for(fontfamilies.options)$$fontfamilies.options$$sep$,$endfor$]{$fontfamilies.font$}
+$endfor$
+$if(mathfont)$
+$if(mathspec)$
+  \ifxetex
+    \setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \else
+    \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+  \fi
+$else$
+  \setmathfont[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$}
+$endif$
+$endif$
+$if(CJKmainfont)$
+  \ifxetex
+    \usepackage{xeCJK}
+    \setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+$if(luatexjapresetoptions)$
+  \ifluatex
+    \usepackage[$for(luatexjapresetoptions)$$luatexjapresetoptions$$sep$,$endfor$]{luatexja-preset}
+  \fi
+$endif$
+$if(CJKmainfont)$
+  \ifluatex
+    \usepackage[$for(luatexjafontspecoptions)$$luatexjafontspecoptions$$sep$,$endfor$]{luatexja-fontspec}
+    \setmainjfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$}
+  \fi
+$endif$
+\fi
+$if(beamer)$
+$if(theme)$
+\usetheme[$for(themeoptions)$$themeoptions$$sep$,$endfor$]{$theme$}
+$endif$
+$if(colortheme)$
+\usecolortheme{$colortheme$}
+$endif$
+$if(fonttheme)$
+\usefonttheme{$fonttheme$}
+$endif$
+$if(mainfont)$
+\usefonttheme{serif} % use mainfont rather than sansfont for slide text
+$endif$
+$if(innertheme)$
+\useinnertheme{$innertheme$}
+$endif$
+$if(outertheme)$
+\useoutertheme{$outertheme$}
+$endif$
+$endif$
+% Use upquote if available, for straight quotes in verbatim environments
+\IfFileExists{upquote.sty}{\usepackage{upquote}}{}
+\IfFileExists{microtype.sty}{% use microtype if available
+  \usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
+  \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
+}{}
+$if(indent)$
+$else$
+\makeatletter
+\@ifundefined{KOMAClassName}{% if non-KOMA class
+  \IfFileExists{parskip.sty}{%
+    \usepackage{parskip}
+  }{% else
+    \setlength{\parindent}{0pt}
+    \setlength{\parskip}{6pt plus 2pt minus 1pt}}
+}{% if KOMA class
+  \KOMAoptions{parskip=half}}
+\makeatother
+$endif$
+$if(verbatim-in-note)$
+\usepackage{fancyvrb}
+$endif$
+\usepackage{xcolor}
+\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
+\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}}
+\hypersetup{
+colorlinks=true,
+linkcolor=blue,
+filecolor=magenta,
+urlcolor=cyan,
+$if(title-meta)$
+  pdftitle={$title-meta$},
+$endif$
+$if(author-meta)$
+  pdfauthor={$author-meta$},
+$endif$
+$if(lang)$
+  pdflang={$lang$},
+$endif$
+$if(subject)$
+  pdfsubject={$subject$},
+$endif$
+$if(keywords)$
+  pdfkeywords={$for(keywords)$$keywords$$sep$, $endfor$},
+$endif$
+$if(colorlinks)$
+  colorlinks=true,
+  linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$,
+  filecolor=$if(filecolor)$$filecolor$$else$Maroon$endif$,
+  citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$,
+  urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$,
+$else$
+  colorlinks=true,
+  linkcolor=blue,
+  filecolor=magenta,
+  urlcolor=cyan,
+$endif$
+  pdfcreator={LaTeX via pandoc}}
+\urlstyle{same} % disable monospaced font for URLs
+$if(verbatim-in-note)$
+\VerbatimFootnotes % allow verbatim text in footnotes
+$endif$
+$if(geometry)$
+$if(beamer)$
+\geometry{$for(geometry)$$geometry$$sep$,$endfor$}
+$else$
+\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
+$endif$
+$endif$
+$if(beamer)$
+\newif\ifbibliography
+$endif$
+$if(listings)$
+\usepackage{listings}
+\newcommand{\passthrough}[1]{#1}
+\lstset{defaultdialect=[5.3]Lua}
+\lstset{defaultdialect=[x86masm]Assembler}
+$endif$
+$if(lhs)$
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
+$endif$
+$if(highlighting-macros)$
+$highlighting-macros$
+$endif$
+$if(tables)$
+\usepackage{longtable,booktabs,array}
+\usepackage{calc} % for calculating minipage widths
+$if(beamer)$
+\usepackage{caption}
+% Make caption package work with longtable
+\makeatletter
+\def\fnum@table{\tablename~\thetable}
+\makeatother
+$else$
+% Correct order of tables after \paragraph or \subparagraph
+\usepackage{etoolbox}
+\makeatletter
+\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
+\makeatother
+% Allow footnotes in longtable head/foot
+\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
+\makesavenoteenv{longtable}
+$endif$
+$endif$
+$if(graphics)$
+\usepackage{graphicx}
+\makeatletter
+\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
+\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
+\makeatother
+% Scale images if necessary, so that they will not overflow the page
+% margins by default, and it is still possible to overwrite the defaults
+% using explicit options in \includegraphics[width, height, ...]{}
+\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
+% Set default figure placement to htbp
+\makeatletter
+\def\fps@figure{htbp}
+\makeatother
+$endif$
+$if(links-as-notes)$
+% Make links footnotes instead of hotlinks:
+\DeclareRobustCommand{\href}[2]{#2\footnote{\url{#1}}}
+$endif$
+$if(strikeout)$
+\usepackage[normalem]{ulem}
+% Avoid problems with \sout in headers with hyperref
+\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
+$endif$
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+$if(numbersections)$
+\setcounter{secnumdepth}{$if(secnumdepth)$$secnumdepth$$else$5$endif$}
+$else$
+\setcounter{secnumdepth}{-\maxdimen} % remove section numbering
+$endif$
+$if(beamer)$
+$else$
+$if(block-headings)$
+% Make \paragraph and \subparagraph free-standing
+\ifx\paragraph\undefined\else
+  \let\oldparagraph\paragraph
+  \renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+  \let\oldsubparagraph\subparagraph
+  \renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+$endif$
+$endif$
+$if(pagestyle)$
+\pagestyle{$pagestyle$}
+$endif$
+$for(header-includes)$
+$header-includes$
+$endfor$
+$if(lang)$
+\ifxetex
+  % Load polyglossia as late as possible: uses bidi with RTL langages (e.g. Hebrew, Arabic)
+  \usepackage{polyglossia}
+  \setmainlanguage[$for(polyglossia-lang.options)$$polyglossia-lang.options$$sep$,$endfor$]{$polyglossia-lang.name$}
+$for(polyglossia-otherlangs)$
+  \setotherlanguage[$for(polyglossia-otherlangs.options)$$polyglossia-otherlangs.options$$sep$,$endfor$]{$polyglossia-otherlangs.name$}
+$endfor$
+\else
+  \usepackage[$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
+% get rid of language-specific shorthands (see #6817):
+\let\LanguageShortHands\languageshorthands
+\def\languageshorthands#1{}
+$if(babel-newcommands)$
+  $babel-newcommands$
+$endif$
+\fi
+$endif$
+\ifluatex
+  \usepackage{selnolig}  % disable illegal ligatures
+\fi
+$if(dir)$
+\ifxetex
+  % Load bidi as late as possible as it modifies e.g. graphicx
+  \usepackage{bidi}
+\fi
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+  \TeXXeTstate=1
+  \newcommand{\RL}[1]{\beginR #1\endR}
+  \newcommand{\LR}[1]{\beginL #1\endL}
+  \newenvironment{RTL}{\beginR}{\endR}
+  \newenvironment{LTR}{\beginL}{\endL}
+\fi
+$endif$
+$if(natbib)$
+\usepackage[$natbiboptions$]{natbib}
+\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
+$endif$
+$if(biblatex)$
+\usepackage[$if(biblio-style)$style=$biblio-style$,$endif$$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$]{biblatex}
+$for(bibliography)$
+\addbibresource{$bibliography$}
+$endfor$
+$endif$
+$if(csl-refs)$
+\newlength{\cslhangindent}
+\setlength{\cslhangindent}{1.5em}
+\newlength{\csllabelwidth}
+\setlength{\csllabelwidth}{3em}
+\newenvironment{CSLReferences}[2] % #1 hanging-ident, #2 entry spacing
+ {% don't indent paragraphs
+  \setlength{\parindent}{0pt}
+  % turn on hanging indent if param 1 is 1
+  \ifodd #1 \everypar{\setlength{\hangindent}{\cslhangindent}}\ignorespaces\fi
+  % set entry spacing
+  \ifnum #2 > 0
+  \setlength{\parskip}{#2\baselineskip}
+  \fi
+ }%
+ {}
+\usepackage{calc}
+\newcommand{\CSLBlock}[1]{#1\hfill\break}
+\newcommand{\CSLLeftMargin}[1]{\parbox[t]{\csllabelwidth}{#1}}
+\newcommand{\CSLRightInline}[1]{\parbox[t]{\linewidth - \csllabelwidth}{#1}\break}
+\newcommand{\CSLIndent}[1]{\hspace{\cslhangindent}#1}
+$endif$
+$if(csquotes)$
+\usepackage{csquotes}
+$endif$
+
+$if(title)$
+\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
+$endif$
+$if(subtitle)$
+$if(beamer)$
+$else$
+\usepackage{etoolbox}
+\makeatletter
+\providecommand{\subtitle}[1]{% add subtitle to \maketitle
+  \apptocmd{\@title}{\par {\large #1 \par}}{}{}
+}
+\makeatother
+$endif$
+\subtitle{$subtitle$}
+$endif$
+\author{$for(author)$$author$$sep$ \and $endfor$}
+\date{$date$}
+$if(beamer)$
+$if(institute)$
+\institute{$for(institute)$$institute$$sep$ \and $endfor$}
+$endif$
+$if(titlegraphic)$
+\titlegraphic{\includegraphics{$titlegraphic$}}
+$endif$
+$if(logo)$
+\logo{\includegraphics{$logo$}}
+$endif$
+$endif$
+
+\begin{document}
+$if(has-frontmatter)$
+\frontmatter
+$endif$
+$if(title)$
+$if(beamer)$
+\frame{\titlepage}
+$else$
+\maketitle
+$endif$
+$if(abstract)$
+\begin{abstract}
+$abstract$
+\end{abstract}
+$endif$
+$endif$
+
+$for(include-before)$
+$include-before$
+
+$endfor$
+$if(toc)$
+$if(toc-title)$
+\renewcommand*\contentsname{$toc-title$}
+$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]
+$if(toc-title)$
+  \frametitle{$toc-title$}
+$endif$
+  \tableofcontents[hideallsubsections]
+\end{frame}
+$else$
+{
+$if(colorlinks)$
+\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$$endif$}
+$endif$
+\setcounter{tocdepth}{$toc-depth$}
+\tableofcontents
+}
+$endif$
+$endif$
+$if(lot)$
+\listoftables
+$endif$
+$if(lof)$
+\listoffigures
+$endif$
+$if(linestretch)$
+\setstretch{$linestretch$}
+$endif$
+$if(has-frontmatter)$
+\mainmatter
+$endif$
+$body$
+
+$if(has-frontmatter)$
+\backmatter
+$endif$
+$if(natbib)$
+$if(bibliography)$
+$if(biblio-title)$
+$if(has-chapters)$
+\renewcommand\bibname{$biblio-title$}
+$else$
+\renewcommand\refname{$biblio-title$}
+$endif$
+$endif$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+  \bibliographytrue
+$endif$
+  \bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$}
+$if(beamer)$
+\end{frame}
+$endif$
+
+$endif$
+$endif$
+$if(biblatex)$
+$if(beamer)$
+\begin{frame}[allowframebreaks]{$biblio-title$}
+  \bibliographytrue
+  \printbibliography[heading=none]
+\end{frame}
+$else$
+\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$
+$endif$
+
+$endif$
+$for(include-after)$
+$include-after$
+
+$endfor$
+\end{document}

BIN
dot-config/setup/templates/xournalpp/dotted.xopp


+ 9 - 0
dot-config/setup/templates/xournalpp/nx

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# TeX template for a beamer presentation
+
+# exit if no argument given
+[ -z "$*" ] && echo "Error: Usage: nx [filename]" && exit
+
+cp ~/.config/setup/templates/xournalpp/dotted.xopp .
+mv dotted.xopp "${1%.*}.xopp"

+ 15 - 0
dot-config/user-dirs.dirs

@@ -0,0 +1,15 @@
+# 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_DOCUMENTS_DIR="$HOME/dox"
+XDG_DOWNLOAD_DIR="$HOME/dl"
+XDG_MUSIC_DIR="$HOME/mus"
+XDG_PICTURES_DIR="$HOME/pix"
+XDG_VIDEOS_DIR="$HOME/vids"
+XDG_DESKTOP_DIR="$HOME/.local/share/desktop"
+XDG_TEMPLATES_DIR="$HOME/.local/share/templates"
+XDG_PUBLICSHARE_DIR="$HOME/.local/share/public"

+ 2788 - 0
dot-config/vim/autoload/plug.vim

@@ -0,0 +1,2788 @@
+" vim-plug: Vim plugin manager
+" ============================
+"
+" Download plug.vim and put it in ~/.vim/autoload
+"
+"   curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
+"     https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
+"
+" Edit your .vimrc
+"
+"   call plug#begin('~/.vim/plugged')
+"
+"   " Make sure you use single quotes
+"
+"   " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align
+"   Plug 'junegunn/vim-easy-align'
+"
+"   " Any valid git URL is allowed
+"   Plug 'https://github.com/junegunn/vim-github-dashboard.git'
+"
+"   " Multiple Plug commands can be written in a single line using | separators
+"   Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets'
+"
+"   " On-demand loading
+"   Plug 'scrooloose/nerdtree', { 'on':  'NERDTreeToggle' }
+"   Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
+"
+"   " Using a non-default branch
+"   Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }
+"
+"   " Using a tagged release; wildcard allowed (requires git 1.9.2 or above)
+"   Plug 'fatih/vim-go', { 'tag': '*' }
+"
+"   " Plugin options
+"   Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' }
+"
+"   " Plugin outside ~/.vim/plugged with post-update hook
+"   Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
+"
+"   " Unmanaged plugin (manually installed and updated)
+"   Plug '~/my-prototype-plugin'
+"
+"   " Initialize plugin system
+"   call plug#end()
+"
+" Then reload .vimrc and :PlugInstall to install plugins.
+"
+" Plug options:
+"
+"| Option                  | Description                                      |
+"| ----------------------- | ------------------------------------------------ |
+"| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use       |
+"| `rtp`                   | Subdirectory that contains Vim plugin            |
+"| `dir`                   | Custom directory for the plugin                  |
+"| `as`                    | Use different name for the plugin                |
+"| `do`                    | Post-update hook (string or funcref)             |
+"| `on`                    | On-demand loading: Commands or `<Plug>`-mappings |
+"| `for`                   | On-demand loading: File types                    |
+"| `frozen`                | Do not update unless explicitly specified        |
+"
+" More information: https://github.com/junegunn/vim-plug
+"
+"
+" Copyright (c) 2017 Junegunn Choi
+"
+" MIT License
+"
+" Permission is hereby granted, free of charge, to any person obtaining
+" a copy of this software and associated documentation files (the
+" "Software"), to deal in the Software without restriction, including
+" without limitation the rights to use, copy, modify, merge, publish,
+" distribute, sublicense, and/or sell copies of the Software, and to
+" permit persons to whom the Software is furnished to do so, subject to
+" the following conditions:
+"
+" The above copyright notice and this permission notice shall be
+" included in all copies or substantial portions of the Software.
+"
+" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+if exists('g:loaded_plug')
+  finish
+endif
+let g:loaded_plug = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+let s:plug_src = 'https://github.com/junegunn/vim-plug.git'
+let s:plug_tab = get(s:, 'plug_tab', -1)
+let s:plug_buf = get(s:, 'plug_buf', -1)
+let s:mac_gui = has('gui_macvim') && has('gui_running')
+let s:is_win = has('win32')
+let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win)
+let s:vim8 = has('patch-8.0.0039') && exists('*job_start')
+if s:is_win && &shellslash
+  set noshellslash
+  let s:me = resolve(expand('<sfile>:p'))
+  set shellslash
+else
+  let s:me = resolve(expand('<sfile>:p'))
+endif
+let s:base_spec = { 'branch': '', 'frozen': 0 }
+let s:TYPE = {
+\   'string':  type(''),
+\   'list':    type([]),
+\   'dict':    type({}),
+\   'funcref': type(function('call'))
+\ }
+let s:loaded = get(s:, 'loaded', {})
+let s:triggers = get(s:, 'triggers', {})
+
+function! s:isabsolute(dir) abort
+  return a:dir =~# '^/' || (has('win32') && a:dir =~? '^\%(\\\|[A-Z]:\)')
+endfunction
+
+function! s:git_dir(dir) abort
+  let gitdir = s:trim(a:dir) . '/.git'
+  if isdirectory(gitdir)
+    return gitdir
+  endif
+  if !filereadable(gitdir)
+    return ''
+  endif
+  let gitdir = matchstr(get(readfile(gitdir), 0, ''), '^gitdir: \zs.*')
+  if len(gitdir) && !s:isabsolute(gitdir)
+    let gitdir = a:dir . '/' . gitdir
+  endif
+  return isdirectory(gitdir) ? gitdir : ''
+endfunction
+
+function! s:git_origin_url(dir) abort
+  let gitdir = s:git_dir(a:dir)
+  let config = gitdir . '/config'
+  if empty(gitdir) || !filereadable(config)
+    return ''
+  endif
+  return matchstr(join(readfile(config)), '\[remote "origin"\].\{-}url\s*=\s*\zs\S*\ze')
+endfunction
+
+function! s:git_revision(dir) abort
+  let gitdir = s:git_dir(a:dir)
+  let head = gitdir . '/HEAD'
+  if empty(gitdir) || !filereadable(head)
+    return ''
+  endif
+
+  let line = get(readfile(head), 0, '')
+  let ref = matchstr(line, '^ref: \zs.*')
+  if empty(ref)
+    return line
+  endif
+
+  if filereadable(gitdir . '/' . ref)
+    return get(readfile(gitdir . '/' . ref), 0, '')
+  endif
+
+  if filereadable(gitdir . '/packed-refs')
+    for line in readfile(gitdir . '/packed-refs')
+      if line =~# ' ' . ref
+        return matchstr(line, '^[0-9a-f]*')
+      endif
+    endfor
+  endif
+
+  return ''
+endfunction
+
+function! s:git_local_branch(dir) abort
+  let gitdir = s:git_dir(a:dir)
+  let head = gitdir . '/HEAD'
+  if empty(gitdir) || !filereadable(head)
+    return ''
+  endif
+  let branch = matchstr(get(readfile(head), 0, ''), '^ref: refs/heads/\zs.*')
+  return len(branch) ? branch : 'HEAD'
+endfunction
+
+function! s:git_origin_branch(spec)
+  if len(a:spec.branch)
+    return a:spec.branch
+  endif
+
+  " The file may not be present if this is a local repository
+  let gitdir = s:git_dir(a:spec.dir)
+  let origin_head = gitdir.'/refs/remotes/origin/HEAD'
+  if len(gitdir) && filereadable(origin_head)
+    return matchstr(get(readfile(origin_head), 0, ''),
+                  \ '^ref: refs/remotes/origin/\zs.*')
+  endif
+
+  " The command may not return the name of a branch in detached HEAD state
+  let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir))
+  return v:shell_error ? '' : result[-1]
+endfunction
+
+if s:is_win
+  function! s:plug_call(fn, ...)
+    let shellslash = &shellslash
+    try
+      set noshellslash
+      return call(a:fn, a:000)
+    finally
+      let &shellslash = shellslash
+    endtry
+  endfunction
+else
+  function! s:plug_call(fn, ...)
+    return call(a:fn, a:000)
+  endfunction
+endif
+
+function! s:plug_getcwd()
+  return s:plug_call('getcwd')
+endfunction
+
+function! s:plug_fnamemodify(fname, mods)
+  return s:plug_call('fnamemodify', a:fname, a:mods)
+endfunction
+
+function! s:plug_expand(fmt)
+  return s:plug_call('expand', a:fmt, 1)
+endfunction
+
+function! s:plug_tempname()
+  return s:plug_call('tempname')
+endfunction
+
+function! plug#begin(...)
+  if a:0 > 0
+    let s:plug_home_org = a:1
+    let home = s:path(s:plug_fnamemodify(s:plug_expand(a:1), ':p'))
+  elseif exists('g:plug_home')
+    let home = s:path(g:plug_home)
+  elseif !empty(&rtp)
+    let home = s:path(split(&rtp, ',')[0]) . '/plugged'
+  else
+    return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.')
+  endif
+  if s:plug_fnamemodify(home, ':t') ==# 'plugin' && s:plug_fnamemodify(home, ':h') ==# s:first_rtp
+    return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.')
+  endif
+
+  let g:plug_home = home
+  let g:plugs = {}
+  let g:plugs_order = []
+  let s:triggers = {}
+
+  call s:define_commands()
+  return 1
+endfunction
+
+function! s:define_commands()
+  command! -nargs=+ -bar Plug call plug#(<args>)
+  if !executable('git')
+    return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.')
+  endif
+  if has('win32')
+  \ && &shellslash
+  \ && (&shell =~# 'cmd\(\.exe\)\?$' || &shell =~# 'powershell\(\.exe\)\?$')
+    return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.')
+  endif
+  if !has('nvim')
+    \ && (has('win32') || has('win32unix'))
+    \ && !has('multi_byte')
+    return s:err('Vim needs +multi_byte feature on Windows to run shell commands. Enable +iconv for best results.')
+  endif
+  command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(<bang>0, [<f-args>])
+  command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate  call s:update(<bang>0, [<f-args>])
+  command! -nargs=0 -bar -bang PlugClean call s:clean(<bang>0)
+  command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif
+  command! -nargs=0 -bar PlugStatus  call s:status()
+  command! -nargs=0 -bar PlugDiff    call s:diff()
+  command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(<bang>0, <f-args>)
+endfunction
+
+function! s:to_a(v)
+  return type(a:v) == s:TYPE.list ? a:v : [a:v]
+endfunction
+
+function! s:to_s(v)
+  return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n"
+endfunction
+
+function! s:glob(from, pattern)
+  return s:lines(globpath(a:from, a:pattern))
+endfunction
+
+function! s:source(from, ...)
+  let found = 0
+  for pattern in a:000
+    for vim in s:glob(a:from, pattern)
+      execute 'source' s:esc(vim)
+      let found = 1
+    endfor
+  endfor
+  return found
+endfunction
+
+function! s:assoc(dict, key, val)
+  let a:dict[a:key] = add(get(a:dict, a:key, []), a:val)
+endfunction
+
+function! s:ask(message, ...)
+  call inputsave()
+  echohl WarningMsg
+  let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) '))
+  echohl None
+  call inputrestore()
+  echo "\r"
+  return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0
+endfunction
+
+function! s:ask_no_interrupt(...)
+  try
+    return call('s:ask', a:000)
+  catch
+    return 0
+  endtry
+endfunction
+
+function! s:lazy(plug, opt)
+  return has_key(a:plug, a:opt) &&
+        \ (empty(s:to_a(a:plug[a:opt]))         ||
+        \  !isdirectory(a:plug.dir)             ||
+        \  len(s:glob(s:rtp(a:plug), 'plugin')) ||
+        \  len(s:glob(s:rtp(a:plug), 'after/plugin')))
+endfunction
+
+function! plug#end()
+  if !exists('g:plugs')
+    return s:err('plug#end() called without calling plug#begin() first')
+  endif
+
+  if exists('#PlugLOD')
+    augroup PlugLOD
+      autocmd!
+    augroup END
+    augroup! PlugLOD
+  endif
+  let lod = { 'ft': {}, 'map': {}, 'cmd': {} }
+
+  if exists('g:did_load_filetypes')
+    filetype off
+  endif
+  for name in g:plugs_order
+    if !has_key(g:plugs, name)
+      continue
+    endif
+    let plug = g:plugs[name]
+    if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for')
+      let s:loaded[name] = 1
+      continue
+    endif
+
+    if has_key(plug, 'on')
+      let s:triggers[name] = { 'map': [], 'cmd': [] }
+      for cmd in s:to_a(plug.on)
+        if cmd =~? '^<Plug>.\+'
+          if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i'))
+            call s:assoc(lod.map, cmd, name)
+          endif
+          call add(s:triggers[name].map, cmd)
+        elseif cmd =~# '^[A-Z]'
+          let cmd = substitute(cmd, '!*$', '', '')
+          if exists(':'.cmd) != 2
+            call s:assoc(lod.cmd, cmd, name)
+          endif
+          call add(s:triggers[name].cmd, cmd)
+        else
+          call s:err('Invalid `on` option: '.cmd.
+          \ '. Should start with an uppercase letter or `<Plug>`.')
+        endif
+      endfor
+    endif
+
+    if has_key(plug, 'for')
+      let types = s:to_a(plug.for)
+      if !empty(types)
+        augroup filetypedetect
+        call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim')
+        augroup END
+      endif
+      for type in types
+        call s:assoc(lod.ft, type, name)
+      endfor
+    endif
+  endfor
+
+  for [cmd, names] in items(lod.cmd)
+    execute printf(
+    \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)',
+    \ cmd, string(cmd), string(names))
+  endfor
+
+  for [map, names] in items(lod.map)
+    for [mode, map_prefix, key_prefix] in
+          \ [['i', '<C-O>', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']]
+      execute printf(
+      \ '%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, %s, "%s")<CR>',
+      \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix)
+    endfor
+  endfor
+
+  for [ft, names] in items(lod.ft)
+    augroup PlugLOD
+      execute printf('autocmd FileType %s call <SID>lod_ft(%s, %s)',
+            \ ft, string(ft), string(names))
+    augroup END
+  endfor
+
+  call s:reorg_rtp()
+  filetype plugin indent on
+  if has('vim_starting')
+    if has('syntax') && !exists('g:syntax_on')
+      syntax enable
+    end
+  else
+    call s:reload_plugins()
+  endif
+endfunction
+
+function! s:loaded_names()
+  return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)')
+endfunction
+
+function! s:load_plugin(spec)
+  call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim')
+endfunction
+
+function! s:reload_plugins()
+  for name in s:loaded_names()
+    call s:load_plugin(g:plugs[name])
+  endfor
+endfunction
+
+function! s:trim(str)
+  return substitute(a:str, '[\/]\+$', '', '')
+endfunction
+
+function! s:version_requirement(val, min)
+  for idx in range(0, len(a:min) - 1)
+    let v = get(a:val, idx, 0)
+    if     v < a:min[idx] | return 0
+    elseif v > a:min[idx] | return 1
+    endif
+  endfor
+  return 1
+endfunction
+
+function! s:git_version_requirement(...)
+  if !exists('s:git_version')
+    let s:git_version = map(split(split(s:system(['git', '--version']))[2], '\.'), 'str2nr(v:val)')
+  endif
+  return s:version_requirement(s:git_version, a:000)
+endfunction
+
+function! s:progress_opt(base)
+  return a:base && !s:is_win &&
+        \ s:git_version_requirement(1, 7, 1) ? '--progress' : ''
+endfunction
+
+function! s:rtp(spec)
+  return s:path(a:spec.dir . get(a:spec, 'rtp', ''))
+endfunction
+
+if s:is_win
+  function! s:path(path)
+    return s:trim(substitute(a:path, '/', '\', 'g'))
+  endfunction
+
+  function! s:dirpath(path)
+    return s:path(a:path) . '\'
+  endfunction
+
+  function! s:is_local_plug(repo)
+    return a:repo =~? '^[a-z]:\|^[%~]'
+  endfunction
+
+  " Copied from fzf
+  function! s:wrap_cmds(cmds)
+    let cmds = [
+      \ '@echo off',
+      \ 'setlocal enabledelayedexpansion']
+    \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds])
+    \ + ['endlocal']
+    if has('iconv')
+      if !exists('s:codepage')
+        let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0)
+      endif
+      return map(cmds, printf('iconv(v:val."\r", "%s", "cp%d")', &encoding, s:codepage))
+    endif
+    return map(cmds, 'v:val."\r"')
+  endfunction
+
+  function! s:batchfile(cmd)
+    let batchfile = s:plug_tempname().'.bat'
+    call writefile(s:wrap_cmds(a:cmd), batchfile)
+    let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0})
+    if &shell =~# 'powershell\(\.exe\)\?$'
+      let cmd = '& ' . cmd
+    endif
+    return [batchfile, cmd]
+  endfunction
+else
+  function! s:path(path)
+    return s:trim(a:path)
+  endfunction
+
+  function! s:dirpath(path)
+    return substitute(a:path, '[/\\]*$', '/', '')
+  endfunction
+
+  function! s:is_local_plug(repo)
+    return a:repo[0] =~ '[/$~]'
+  endfunction
+endif
+
+function! s:err(msg)
+  echohl ErrorMsg
+  echom '[vim-plug] '.a:msg
+  echohl None
+endfunction
+
+function! s:warn(cmd, msg)
+  echohl WarningMsg
+  execute a:cmd 'a:msg'
+  echohl None
+endfunction
+
+function! s:esc(path)
+  return escape(a:path, ' ')
+endfunction
+
+function! s:escrtp(path)
+  return escape(a:path, ' ,')
+endfunction
+
+function! s:remove_rtp()
+  for name in s:loaded_names()
+    let rtp = s:rtp(g:plugs[name])
+    execute 'set rtp-='.s:escrtp(rtp)
+    let after = globpath(rtp, 'after')
+    if isdirectory(after)
+      execute 'set rtp-='.s:escrtp(after)
+    endif
+  endfor
+endfunction
+
+function! s:reorg_rtp()
+  if !empty(s:first_rtp)
+    execute 'set rtp-='.s:first_rtp
+    execute 'set rtp-='.s:last_rtp
+  endif
+
+  " &rtp is modified from outside
+  if exists('s:prtp') && s:prtp !=# &rtp
+    call s:remove_rtp()
+    unlet! s:middle
+  endif
+
+  let s:middle = get(s:, 'middle', &rtp)
+  let rtps     = map(s:loaded_names(), 's:rtp(g:plugs[v:val])')
+  let afters   = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)')
+  let rtp      = join(map(rtps, 'escape(v:val, ",")'), ',')
+                 \ . ','.s:middle.','
+                 \ . join(map(afters, 'escape(v:val, ",")'), ',')
+  let &rtp     = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g')
+  let s:prtp   = &rtp
+
+  if !empty(s:first_rtp)
+    execute 'set rtp^='.s:first_rtp
+    execute 'set rtp+='.s:last_rtp
+  endif
+endfunction
+
+function! s:doautocmd(...)
+  if exists('#'.join(a:000, '#'))
+    execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '<nomodeline>' : '') join(a:000)
+  endif
+endfunction
+
+function! s:dobufread(names)
+  for name in a:names
+    let path = s:rtp(g:plugs[name])
+    for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin']
+      if len(finddir(dir, path))
+        if exists('#BufRead')
+          doautocmd BufRead
+        endif
+        return
+      endif
+    endfor
+  endfor
+endfunction
+
+function! plug#load(...)
+  if a:0 == 0
+    return s:err('Argument missing: plugin name(s) required')
+  endif
+  if !exists('g:plugs')
+    return s:err('plug#begin was not called')
+  endif
+  let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000
+  let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)')
+  if !empty(unknowns)
+    let s = len(unknowns) > 1 ? 's' : ''
+    return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', ')))
+  end
+  let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)')
+  if !empty(unloaded)
+    for name in unloaded
+      call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
+    endfor
+    call s:dobufread(unloaded)
+    return 1
+  end
+  return 0
+endfunction
+
+function! s:remove_triggers(name)
+  if !has_key(s:triggers, a:name)
+    return
+  endif
+  for cmd in s:triggers[a:name].cmd
+    execute 'silent! delc' cmd
+  endfor
+  for map in s:triggers[a:name].map
+    execute 'silent! unmap' map
+    execute 'silent! iunmap' map
+  endfor
+  call remove(s:triggers, a:name)
+endfunction
+
+function! s:lod(names, types, ...)
+  for name in a:names
+    call s:remove_triggers(name)
+    let s:loaded[name] = 1
+  endfor
+  call s:reorg_rtp()
+
+  for name in a:names
+    let rtp = s:rtp(g:plugs[name])
+    for dir in a:types
+      call s:source(rtp, dir.'/**/*.vim')
+    endfor
+    if a:0
+      if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2))
+        execute 'runtime' a:1
+      endif
+      call s:source(rtp, a:2)
+    endif
+    call s:doautocmd('User', name)
+  endfor
+endfunction
+
+function! s:lod_ft(pat, names)
+  let syn = 'syntax/'.a:pat.'.vim'
+  call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn)
+  execute 'autocmd! PlugLOD FileType' a:pat
+  call s:doautocmd('filetypeplugin', 'FileType')
+  call s:doautocmd('filetypeindent', 'FileType')
+endfunction
+
+function! s:lod_cmd(cmd, bang, l1, l2, args, names)
+  call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
+  call s:dobufread(a:names)
+  execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
+endfunction
+
+function! s:lod_map(map, names, with_prefix, prefix)
+  call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
+  call s:dobufread(a:names)
+  let extra = ''
+  while 1
+    let c = getchar(0)
+    if c == 0
+      break
+    endif
+    let extra .= nr2char(c)
+  endwhile
+
+  if a:with_prefix
+    let prefix = v:count ? v:count : ''
+    let prefix .= '"'.v:register.a:prefix
+    if mode(1) == 'no'
+      if v:operator == 'c'
+        let prefix = "\<esc>" . prefix
+      endif
+      let prefix .= v:operator
+    endif
+    call feedkeys(prefix, 'n')
+  endif
+  call feedkeys(substitute(a:map, '^<Plug>', "\<Plug>", '') . extra)
+endfunction
+
+function! plug#(repo, ...)
+  if a:0 > 1
+    return s:err('Invalid number of arguments (1..2)')
+  endif
+
+  try
+    let repo = s:trim(a:repo)
+    let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec
+    let name = get(opts, 'as', s:plug_fnamemodify(repo, ':t:s?\.git$??'))
+    let spec = extend(s:infer_properties(name, repo), opts)
+    if !has_key(g:plugs, name)
+      call add(g:plugs_order, name)
+    endif
+    let g:plugs[name] = spec
+    let s:loaded[name] = get(s:loaded, name, 0)
+  catch
+    return s:err(repo . ' ' . v:exception)
+  endtry
+endfunction
+
+function! s:parse_options(arg)
+  let opts = copy(s:base_spec)
+  let type = type(a:arg)
+  let opt_errfmt = 'Invalid argument for "%s" option of :Plug (expected: %s)'
+  if type == s:TYPE.string
+    if empty(a:arg)
+      throw printf(opt_errfmt, 'tag', 'string')
+    endif
+    let opts.tag = a:arg
+  elseif type == s:TYPE.dict
+    for opt in ['branch', 'tag', 'commit', 'rtp', 'dir', 'as']
+      if has_key(a:arg, opt)
+      \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))
+        throw printf(opt_errfmt, opt, 'string')
+      endif
+    endfor
+    for opt in ['on', 'for']
+      if has_key(a:arg, opt)
+      \ && type(a:arg[opt]) != s:TYPE.list
+      \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))
+        throw printf(opt_errfmt, opt, 'string or list')
+      endif
+    endfor
+    if has_key(a:arg, 'do')
+      \ && type(a:arg.do) != s:TYPE.funcref
+      \ && (type(a:arg.do) != s:TYPE.string || empty(a:arg.do))
+        throw printf(opt_errfmt, 'do', 'string or funcref')
+    endif
+    call extend(opts, a:arg)
+    if has_key(opts, 'dir')
+      let opts.dir = s:dirpath(s:plug_expand(opts.dir))
+    endif
+  else
+    throw 'Invalid argument type (expected: string or dictionary)'
+  endif
+  return opts
+endfunction
+
+function! s:infer_properties(name, repo)
+  let repo = a:repo
+  if s:is_local_plug(repo)
+    return { 'dir': s:dirpath(s:plug_expand(repo)) }
+  else
+    if repo =~ ':'
+      let uri = repo
+    else
+      if repo !~ '/'
+        throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo)
+      endif
+      let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git')
+      let uri = printf(fmt, repo)
+    endif
+    return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri }
+  endif
+endfunction
+
+function! s:install(force, names)
+  call s:update_impl(0, a:force, a:names)
+endfunction
+
+function! s:update(force, names)
+  call s:update_impl(1, a:force, a:names)
+endfunction
+
+function! plug#helptags()
+  if !exists('g:plugs')
+    return s:err('plug#begin was not called')
+  endif
+  for spec in values(g:plugs)
+    let docd = join([s:rtp(spec), 'doc'], '/')
+    if isdirectory(docd)
+      silent! execute 'helptags' s:esc(docd)
+    endif
+  endfor
+  return 1
+endfunction
+
+function! s:syntax()
+  syntax clear
+  syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber
+  syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX
+  syn match plugNumber /[0-9]\+[0-9.]*/ contained
+  syn match plugBracket /[[\]]/ contained
+  syn match plugX /x/ contained
+  syn match plugDash /^-\{1}\ /
+  syn match plugPlus /^+/
+  syn match plugStar /^*/
+  syn match plugMessage /\(^- \)\@<=.*/
+  syn match plugName /\(^- \)\@<=[^ ]*:/
+  syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/
+  syn match plugTag /(tag: [^)]\+)/
+  syn match plugInstall /\(^+ \)\@<=[^:]*/
+  syn match plugUpdate /\(^* \)\@<=[^:]*/
+  syn match plugCommit /^  \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag
+  syn match plugEdge /^  \X\+$/
+  syn match plugEdge /^  \X*/ contained nextgroup=plugSha
+  syn match plugSha /[0-9a-f]\{7,9}/ contained
+  syn match plugRelDate /([^)]*)$/ contained
+  syn match plugNotLoaded /(not loaded)$/
+  syn match plugError /^x.*/
+  syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/
+  syn match plugH2 /^.*:\n-\+$/
+  syn match plugH2 /^-\{2,}/
+  syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
+  hi def link plug1       Title
+  hi def link plug2       Repeat
+  hi def link plugH2      Type
+  hi def link plugX       Exception
+  hi def link plugBracket Structure
+  hi def link plugNumber  Number
+
+  hi def link plugDash    Special
+  hi def link plugPlus    Constant
+  hi def link plugStar    Boolean
+
+  hi def link plugMessage Function
+  hi def link plugName    Label
+  hi def link plugInstall Function
+  hi def link plugUpdate  Type
+
+  hi def link plugError   Error
+  hi def link plugDeleted Ignore
+  hi def link plugRelDate Comment
+  hi def link plugEdge    PreProc
+  hi def link plugSha     Identifier
+  hi def link plugTag     Constant
+
+  hi def link plugNotLoaded Comment
+endfunction
+
+function! s:lpad(str, len)
+  return a:str . repeat(' ', a:len - len(a:str))
+endfunction
+
+function! s:lines(msg)
+  return split(a:msg, "[\r\n]")
+endfunction
+
+function! s:lastline(msg)
+  return get(s:lines(a:msg), -1, '')
+endfunction
+
+function! s:new_window()
+  execute get(g:, 'plug_window', 'vertical topleft new')
+endfunction
+
+function! s:plug_window_exists()
+  let buflist = tabpagebuflist(s:plug_tab)
+  return !empty(buflist) && index(buflist, s:plug_buf) >= 0
+endfunction
+
+function! s:switch_in()
+  if !s:plug_window_exists()
+    return 0
+  endif
+
+  if winbufnr(0) != s:plug_buf
+    let s:pos = [tabpagenr(), winnr(), winsaveview()]
+    execute 'normal!' s:plug_tab.'gt'
+    let winnr = bufwinnr(s:plug_buf)
+    execute winnr.'wincmd w'
+    call add(s:pos, winsaveview())
+  else
+    let s:pos = [winsaveview()]
+  endif
+
+  setlocal modifiable
+  return 1
+endfunction
+
+function! s:switch_out(...)
+  call winrestview(s:pos[-1])
+  setlocal nomodifiable
+  if a:0 > 0
+    execute a:1
+  endif
+
+  if len(s:pos) > 1
+    execute 'normal!' s:pos[0].'gt'
+    execute s:pos[1] 'wincmd w'
+    call winrestview(s:pos[2])
+  endif
+endfunction
+
+function! s:finish_bindings()
+  nnoremap <silent> <buffer> R  :call <SID>retry()<cr>
+  nnoremap <silent> <buffer> D  :PlugDiff<cr>
+  nnoremap <silent> <buffer> S  :PlugStatus<cr>
+  nnoremap <silent> <buffer> U  :call <SID>status_update()<cr>
+  xnoremap <silent> <buffer> U  :call <SID>status_update()<cr>
+  nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr>
+  nnoremap <silent> <buffer> [[ :silent! call <SID>section('b')<cr>
+endfunction
+
+function! s:prepare(...)
+  if empty(s:plug_getcwd())
+    throw 'Invalid current working directory. Cannot proceed.'
+  endif
+
+  for evar in ['$GIT_DIR', '$GIT_WORK_TREE']
+    if exists(evar)
+      throw evar.' detected. Cannot proceed.'
+    endif
+  endfor
+
+  call s:job_abort()
+  if s:switch_in()
+    if b:plug_preview == 1
+      pc
+    endif
+    enew
+  else
+    call s:new_window()
+  endif
+
+  nnoremap <silent> <buffer> q  :if b:plug_preview==1<bar>pc<bar>endif<bar>bd<cr>
+  if a:0 == 0
+    call s:finish_bindings()
+  endif
+  let b:plug_preview = -1
+  let s:plug_tab = tabpagenr()
+  let s:plug_buf = winbufnr(0)
+  call s:assign_name()
+
+  for k in ['<cr>', 'L', 'o', 'X', 'd', 'dd']
+    execute 'silent! unmap <buffer>' k
+  endfor
+  setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell
+  if exists('+colorcolumn')
+    setlocal colorcolumn=
+  endif
+  setf vim-plug
+  if exists('g:syntax_on')
+    call s:syntax()
+  endif
+endfunction
+
+function! s:assign_name()
+  " Assign buffer name
+  let prefix = '[Plugins]'
+  let name   = prefix
+  let idx    = 2
+  while bufexists(name)
+    let name = printf('%s (%s)', prefix, idx)
+    let idx = idx + 1
+  endwhile
+  silent! execute 'f' fnameescape(name)
+endfunction
+
+function! s:chsh(swap)
+  let prev = [&shell, &shellcmdflag, &shellredir]
+  if !s:is_win
+    set shell=sh
+  endif
+  if a:swap
+    if &shell =~# 'powershell\(\.exe\)\?$' || &shell =~# 'pwsh$'
+      let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s'
+    elseif &shell =~# 'sh' || &shell =~# 'cmd\(\.exe\)\?$'
+      set shellredir=>%s\ 2>&1
+    endif
+  endif
+  return prev
+endfunction
+
+function! s:bang(cmd, ...)
+  let batchfile = ''
+  try
+    let [sh, shellcmdflag, shrd] = s:chsh(a:0)
+    " FIXME: Escaping is incomplete. We could use shellescape with eval,
+    "        but it won't work on Windows.
+    let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd
+    if s:is_win
+      let [batchfile, cmd] = s:batchfile(cmd)
+    endif
+    let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%')
+    execute "normal! :execute g:_plug_bang\<cr>\<cr>"
+  finally
+    unlet g:_plug_bang
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win && filereadable(batchfile)
+      call delete(batchfile)
+    endif
+  endtry
+  return v:shell_error ? 'Exit status: ' . v:shell_error : ''
+endfunction
+
+function! s:regress_bar()
+  let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '')
+  call s:progress_bar(2, bar, len(bar))
+endfunction
+
+function! s:is_updated(dir)
+  return !empty(s:system_chomp(['git', 'log', '--pretty=format:%h', 'HEAD...HEAD@{1}'], a:dir))
+endfunction
+
+function! s:do(pull, force, todo)
+  for [name, spec] in items(a:todo)
+    if !isdirectory(spec.dir)
+      continue
+    endif
+    let installed = has_key(s:update.new, name)
+    let updated = installed ? 0 :
+      \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir))
+    if a:force || installed || updated
+      execute 'cd' s:esc(spec.dir)
+      call append(3, '- Post-update hook for '. name .' ... ')
+      let error = ''
+      let type = type(spec.do)
+      if type == s:TYPE.string
+        if spec.do[0] == ':'
+          if !get(s:loaded, name, 0)
+            let s:loaded[name] = 1
+            call s:reorg_rtp()
+          endif
+          call s:load_plugin(spec)
+          try
+            execute spec.do[1:]
+          catch
+            let error = v:exception
+          endtry
+          if !s:plug_window_exists()
+            cd -
+            throw 'Warning: vim-plug was terminated by the post-update hook of '.name
+          endif
+        else
+          let error = s:bang(spec.do)
+        endif
+      elseif type == s:TYPE.funcref
+        try
+          call s:load_plugin(spec)
+          let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')
+          call spec.do({ 'name': name, 'status': status, 'force': a:force })
+        catch
+          let error = v:exception
+        endtry
+      else
+        let error = 'Invalid hook type'
+      endif
+      call s:switch_in()
+      call setline(4, empty(error) ? (getline(4) . 'OK')
+                                 \ : ('x' . getline(4)[1:] . error))
+      if !empty(error)
+        call add(s:update.errors, name)
+        call s:regress_bar()
+      endif
+      cd -
+    endif
+  endfor
+endfunction
+
+function! s:hash_match(a, b)
+  return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0
+endfunction
+
+function! s:checkout(spec)
+  let sha = a:spec.commit
+  let output = s:git_revision(a:spec.dir)
+  if !empty(output) && !s:hash_match(sha, s:lines(output)[0])
+    let credential_helper = s:git_version_requirement(2) ? '-c credential.helper= ' : ''
+    let output = s:system(
+          \ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)
+  endif
+  return output
+endfunction
+
+function! s:finish(pull)
+  let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen'))
+  if new_frozen
+    let s = new_frozen > 1 ? 's' : ''
+    call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s))
+  endif
+  call append(3, '- Finishing ... ') | 4
+  redraw
+  call plug#helptags()
+  call plug#end()
+  call setline(4, getline(4) . 'Done!')
+  redraw
+  let msgs = []
+  if !empty(s:update.errors)
+    call add(msgs, "Press 'R' to retry.")
+  endif
+  if a:pull && len(s:update.new) < len(filter(getline(5, '$'),
+                \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'"))
+    call add(msgs, "Press 'D' to see the updated changes.")
+  endif
+  echo join(msgs, ' ')
+  call s:finish_bindings()
+endfunction
+
+function! s:retry()
+  if empty(s:update.errors)
+    return
+  endif
+  echo
+  call s:update_impl(s:update.pull, s:update.force,
+        \ extend(copy(s:update.errors), [s:update.threads]))
+endfunction
+
+function! s:is_managed(name)
+  return has_key(g:plugs[a:name], 'uri')
+endfunction
+
+function! s:names(...)
+  return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)'))
+endfunction
+
+function! s:check_ruby()
+  silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'")
+  if !exists('g:plug_ruby')
+    redraw!
+    return s:warn('echom', 'Warning: Ruby interface is broken')
+  endif
+  let ruby_version = split(g:plug_ruby, '\.')
+  unlet g:plug_ruby
+  return s:version_requirement(ruby_version, [1, 8, 7])
+endfunction
+
+function! s:update_impl(pull, force, args) abort
+  let sync = index(a:args, '--sync') >= 0 || has('vim_starting')
+  let args = filter(copy(a:args), 'v:val != "--sync"')
+  let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ?
+                  \ remove(args, -1) : get(g:, 'plug_threads', 16)
+
+  let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
+  let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') :
+                         \ filter(managed, 'index(args, v:key) >= 0')
+
+  if empty(todo)
+    return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install'))
+  endif
+
+  if !s:is_win && s:git_version_requirement(2, 3)
+    let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : ''
+    let $GIT_TERMINAL_PROMPT = 0
+    for plug in values(todo)
+      let plug.uri = substitute(plug.uri,
+            \ '^https://git::@github\.com', 'https://github.com', '')
+    endfor
+  endif
+
+  if !isdirectory(g:plug_home)
+    try
+      call mkdir(g:plug_home, 'p')
+    catch
+      return s:err(printf('Invalid plug directory: %s. '.
+              \ 'Try to call plug#begin with a valid directory', g:plug_home))
+    endtry
+  endif
+
+  if has('nvim') && !exists('*jobwait') && threads > 1
+    call s:warn('echom', '[vim-plug] Update Neovim for parallel installer')
+  endif
+
+  let use_job = s:nvim || s:vim8
+  let python = (has('python') || has('python3')) && !use_job
+  let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby()
+
+  let s:update = {
+    \ 'start':   reltime(),
+    \ 'all':     todo,
+    \ 'todo':    copy(todo),
+    \ 'errors':  [],
+    \ 'pull':    a:pull,
+    \ 'force':   a:force,
+    \ 'new':     {},
+    \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1,
+    \ 'bar':     '',
+    \ 'fin':     0
+  \ }
+
+  call s:prepare(1)
+  call append(0, ['', ''])
+  normal! 2G
+  silent! redraw
+
+  let s:clone_opt = []
+  if get(g:, 'plug_shallow', 1)
+    call extend(s:clone_opt, ['--depth', '1'])
+    if s:git_version_requirement(1, 7, 10)
+      call add(s:clone_opt, '--no-single-branch')
+    endif
+  endif
+
+  if has('win32unix') || has('wsl')
+    call extend(s:clone_opt, ['-c', 'core.eol=lf', '-c', 'core.autocrlf=input'])
+  endif
+
+  let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : ''
+
+  " Python version requirement (>= 2.7)
+  if python && !has('python3') && !ruby && !use_job && s:update.threads > 1
+    redir => pyv
+    silent python import platform; print platform.python_version()
+    redir END
+    let python = s:version_requirement(
+          \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6])
+  endif
+
+  if (python || ruby) && s:update.threads > 1
+    try
+      let imd = &imd
+      if s:mac_gui
+        set noimd
+      endif
+      if ruby
+        call s:update_ruby()
+      else
+        call s:update_python()
+      endif
+    catch
+      let lines = getline(4, '$')
+      let printed = {}
+      silent! 4,$d _
+      for line in lines
+        let name = s:extract_name(line, '.', '')
+        if empty(name) || !has_key(printed, name)
+          call append('$', line)
+          if !empty(name)
+            let printed[name] = 1
+            if line[0] == 'x' && index(s:update.errors, name) < 0
+              call add(s:update.errors, name)
+            end
+          endif
+        endif
+      endfor
+    finally
+      let &imd = imd
+      call s:update_finish()
+    endtry
+  else
+    call s:update_vim()
+    while use_job && sync
+      sleep 100m
+      if s:update.fin
+        break
+      endif
+    endwhile
+  endif
+endfunction
+
+function! s:log4(name, msg)
+  call setline(4, printf('- %s (%s)', a:msg, a:name))
+  redraw
+endfunction
+
+function! s:update_finish()
+  if exists('s:git_terminal_prompt')
+    let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt
+  endif
+  if s:switch_in()
+    call append(3, '- Updating ...') | 4
+    for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))'))
+      let [pos, _] = s:logpos(name)
+      if !pos
+        continue
+      endif
+      if has_key(spec, 'commit')
+        call s:log4(name, 'Checking out '.spec.commit)
+        let out = s:checkout(spec)
+      elseif has_key(spec, 'tag')
+        let tag = spec.tag
+        if tag =~ '\*'
+          let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir))
+          if !v:shell_error && !empty(tags)
+            let tag = tags[0]
+            call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag))
+            call append(3, '')
+          endif
+        endif
+        call s:log4(name, 'Checking out '.tag)
+        let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir)
+      else
+        let branch = s:git_origin_branch(spec)
+        call s:log4(name, 'Merging origin/'.s:esc(branch))
+        let out = s:system('git checkout -q '.plug#shellescape(branch).' -- 2>&1'
+              \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only '.plug#shellescape('origin/'.branch).' 2>&1')), spec.dir)
+      endif
+      if !v:shell_error && filereadable(spec.dir.'/.gitmodules') &&
+            \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir))
+        call s:log4(name, 'Updating submodules. This may take a while.')
+        let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir)
+      endif
+      let msg = s:format_message(v:shell_error ? 'x': '-', name, out)
+      if v:shell_error
+        call add(s:update.errors, name)
+        call s:regress_bar()
+        silent execute pos 'd _'
+        call append(4, msg) | 4
+      elseif !empty(out)
+        call setline(pos, msg[0])
+      endif
+      redraw
+    endfor
+    silent 4 d _
+    try
+      call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")'))
+    catch
+      call s:warn('echom', v:exception)
+      call s:warn('echo', '')
+      return
+    endtry
+    call s:finish(s:update.pull)
+    call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.')
+    call s:switch_out('normal! gg')
+  endif
+endfunction
+
+function! s:job_abort()
+  if (!s:nvim && !s:vim8) || !exists('s:jobs')
+    return
+  endif
+
+  for [name, j] in items(s:jobs)
+    if s:nvim
+      silent! call jobstop(j.jobid)
+    elseif s:vim8
+      silent! call job_stop(j.jobid)
+    endif
+    if j.new
+      call s:rm_rf(g:plugs[name].dir)
+    endif
+  endfor
+  let s:jobs = {}
+endfunction
+
+function! s:last_non_empty_line(lines)
+  let len = len(a:lines)
+  for idx in range(len)
+    let line = a:lines[len-idx-1]
+    if !empty(line)
+      return line
+    endif
+  endfor
+  return ''
+endfunction
+
+function! s:job_out_cb(self, data) abort
+  let self = a:self
+  let data = remove(self.lines, -1) . a:data
+  let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]')
+  call extend(self.lines, lines)
+  " To reduce the number of buffer updates
+  let self.tick = get(self, 'tick', -1) + 1
+  if !self.running || self.tick % len(s:jobs) == 0
+    let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-')
+    let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines)
+    call s:log(bullet, self.name, result)
+  endif
+endfunction
+
+function! s:job_exit_cb(self, data) abort
+  let a:self.running = 0
+  let a:self.error = a:data != 0
+  call s:reap(a:self.name)
+  call s:tick()
+endfunction
+
+function! s:job_cb(fn, job, ch, data)
+  if !s:plug_window_exists() " plug window closed
+    return s:job_abort()
+  endif
+  call call(a:fn, [a:job, a:data])
+endfunction
+
+function! s:nvim_cb(job_id, data, event) dict abort
+  return (a:event == 'stdout' || a:event == 'stderr') ?
+    \ s:job_cb('s:job_out_cb',  self, 0, join(a:data, "\n")) :
+    \ s:job_cb('s:job_exit_cb', self, 0, a:data)
+endfunction
+
+function! s:spawn(name, cmd, opts)
+  let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''],
+            \ 'new': get(a:opts, 'new', 0) }
+  let s:jobs[a:name] = job
+
+  if s:nvim
+    if has_key(a:opts, 'dir')
+      let job.cwd = a:opts.dir
+    endif
+    let argv = a:cmd
+    call extend(job, {
+    \ 'on_stdout': function('s:nvim_cb'),
+    \ 'on_stderr': function('s:nvim_cb'),
+    \ 'on_exit':   function('s:nvim_cb'),
+    \ })
+    let jid = s:plug_call('jobstart', argv, job)
+    if jid > 0
+      let job.jobid = jid
+    else
+      let job.running = 0
+      let job.error   = 1
+      let job.lines   = [jid < 0 ? argv[0].' is not executable' :
+            \ 'Invalid arguments (or job table is full)']
+    endif
+  elseif s:vim8
+    let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"script": 0})'))
+    if has_key(a:opts, 'dir')
+      let cmd = s:with_cd(cmd, a:opts.dir, 0)
+    endif
+    let argv = s:is_win ? ['cmd', '/s', '/c', '"'.cmd.'"'] : ['sh', '-c', cmd]
+    let jid = job_start(s:is_win ? join(argv, ' ') : argv, {
+    \ 'out_cb':   function('s:job_cb', ['s:job_out_cb',  job]),
+    \ 'err_cb':   function('s:job_cb', ['s:job_out_cb',  job]),
+    \ 'exit_cb':  function('s:job_cb', ['s:job_exit_cb', job]),
+    \ 'err_mode': 'raw',
+    \ 'out_mode': 'raw'
+    \})
+    if job_status(jid) == 'run'
+      let job.jobid = jid
+    else
+      let job.running = 0
+      let job.error   = 1
+      let job.lines   = ['Failed to start job']
+    endif
+  else
+    let job.lines = s:lines(call('s:system', has_key(a:opts, 'dir') ? [a:cmd, a:opts.dir] : [a:cmd]))
+    let job.error = v:shell_error != 0
+    let job.running = 0
+  endif
+endfunction
+
+function! s:reap(name)
+  let job = s:jobs[a:name]
+  if job.error
+    call add(s:update.errors, a:name)
+  elseif get(job, 'new', 0)
+    let s:update.new[a:name] = 1
+  endif
+  let s:update.bar .= job.error ? 'x' : '='
+
+  let bullet = job.error ? 'x' : '-'
+  let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines)
+  call s:log(bullet, a:name, empty(result) ? 'OK' : result)
+  call s:bar()
+
+  call remove(s:jobs, a:name)
+endfunction
+
+function! s:bar()
+  if s:switch_in()
+    let total = len(s:update.all)
+    call setline(1, (s:update.pull ? 'Updating' : 'Installing').
+          \ ' plugins ('.len(s:update.bar).'/'.total.')')
+    call s:progress_bar(2, s:update.bar, total)
+    call s:switch_out()
+  endif
+endfunction
+
+function! s:logpos(name)
+  let max = line('$')
+  for i in range(4, max > 4 ? max : 4)
+    if getline(i) =~# '^[-+x*] '.a:name.':'
+      for j in range(i + 1, max > 5 ? max : 5)
+        if getline(j) !~ '^ '
+          return [i, j - 1]
+        endif
+      endfor
+      return [i, i]
+    endif
+  endfor
+  return [0, 0]
+endfunction
+
+function! s:log(bullet, name, lines)
+  if s:switch_in()
+    let [b, e] = s:logpos(a:name)
+    if b > 0
+      silent execute printf('%d,%d d _', b, e)
+      if b > winheight('.')
+        let b = 4
+      endif
+    else
+      let b = 4
+    endif
+    " FIXME For some reason, nomodifiable is set after :d in vim8
+    setlocal modifiable
+    call append(b - 1, s:format_message(a:bullet, a:name, a:lines))
+    call s:switch_out()
+  endif
+endfunction
+
+function! s:update_vim()
+  let s:jobs = {}
+
+  call s:bar()
+  call s:tick()
+endfunction
+
+function! s:tick()
+  let pull = s:update.pull
+  let prog = s:progress_opt(s:nvim || s:vim8)
+while 1 " Without TCO, Vim stack is bound to explode
+  if empty(s:update.todo)
+    if empty(s:jobs) && !s:update.fin
+      call s:update_finish()
+      let s:update.fin = 1
+    endif
+    return
+  endif
+
+  let name = keys(s:update.todo)[0]
+  let spec = remove(s:update.todo, name)
+  let new  = empty(globpath(spec.dir, '.git', 1))
+
+  call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...')
+  redraw
+
+  let has_tag = has_key(spec, 'tag')
+  if !new
+    let [error, _] = s:git_validate(spec, 0)
+    if empty(error)
+      if pull
+        let cmd = s:git_version_requirement(2) ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch']
+        if has_tag && !empty(globpath(spec.dir, '.git/shallow'))
+          call extend(cmd, ['--depth', '99999999'])
+        endif
+        if !empty(prog)
+          call add(cmd, prog)
+        endif
+        call s:spawn(name, cmd, { 'dir': spec.dir })
+      else
+        let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 }
+      endif
+    else
+      let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 }
+    endif
+  else
+    let cmd = ['git', 'clone']
+    if !has_tag
+      call extend(cmd, s:clone_opt)
+    endif
+    if !empty(prog)
+      call add(cmd, prog)
+    endif
+    call s:spawn(name, extend(cmd, [spec.uri, s:trim(spec.dir)]), { 'new': 1 })
+  endif
+
+  if !s:jobs[name].running
+    call s:reap(name)
+  endif
+  if len(s:jobs) >= s:update.threads
+    break
+  endif
+endwhile
+endfunction
+
+function! s:update_python()
+let py_exe = has('python') ? 'python' : 'python3'
+execute py_exe "<< EOF"
+import datetime
+import functools
+import os
+try:
+  import queue
+except ImportError:
+  import Queue as queue
+import random
+import re
+import shutil
+import signal
+import subprocess
+import tempfile
+import threading as thr
+import time
+import traceback
+import vim
+
+G_NVIM = vim.eval("has('nvim')") == '1'
+G_PULL = vim.eval('s:update.pull') == '1'
+G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1
+G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)'))
+G_CLONE_OPT = ' '.join(vim.eval('s:clone_opt'))
+G_PROGRESS = vim.eval('s:progress_opt(1)')
+G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads'))
+G_STOP = thr.Event()
+G_IS_WIN = vim.eval('s:is_win') == '1'
+
+class PlugError(Exception):
+  def __init__(self, msg):
+    self.msg = msg
+class CmdTimedOut(PlugError):
+  pass
+class CmdFailed(PlugError):
+  pass
+class InvalidURI(PlugError):
+  pass
+class Action(object):
+  INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-']
+
+class Buffer(object):
+  def __init__(self, lock, num_plugs, is_pull):
+    self.bar = ''
+    self.event = 'Updating' if is_pull else 'Installing'
+    self.lock = lock
+    self.maxy = int(vim.eval('winheight(".")'))
+    self.num_plugs = num_plugs
+
+  def __where(self, name):
+    """ Find first line with name in current buffer. Return line num. """
+    found, lnum = False, 0
+    matcher = re.compile('^[-+x*] {0}:'.format(name))
+    for line in vim.current.buffer:
+      if matcher.search(line) is not None:
+        found = True
+        break
+      lnum += 1
+
+    if not found:
+      lnum = -1
+    return lnum
+
+  def header(self):
+    curbuf = vim.current.buffer
+    curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs)
+
+    num_spaces = self.num_plugs - len(self.bar)
+    curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ')
+
+    with self.lock:
+      vim.command('normal! 2G')
+      vim.command('redraw')
+
+  def write(self, action, name, lines):
+    first, rest = lines[0], lines[1:]
+    msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)]
+    msg.extend(['    ' + line for line in rest])
+
+    try:
+      if action == Action.ERROR:
+        self.bar += 'x'
+        vim.command("call add(s:update.errors, '{0}')".format(name))
+      elif action == Action.DONE:
+        self.bar += '='
+
+      curbuf = vim.current.buffer
+      lnum = self.__where(name)
+      if lnum != -1: # Found matching line num
+        del curbuf[lnum]
+        if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]):
+          lnum = 3
+      else:
+        lnum = 3
+      curbuf.append(msg, lnum)
+
+      self.header()
+    except vim.error:
+      pass
+
+class Command(object):
+  CD = 'cd /d' if G_IS_WIN else 'cd'
+
+  def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None):
+    self.cmd = cmd
+    if cmd_dir:
+      self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd)
+    self.timeout = timeout
+    self.callback = cb if cb else (lambda msg: None)
+    self.clean = clean if clean else (lambda: None)
+    self.proc = None
+
+  @property
+  def alive(self):
+    """ Returns true only if command still running. """
+    return self.proc and self.proc.poll() is None
+
+  def execute(self, ntries=3):
+    """ Execute the command with ntries if CmdTimedOut.
+        Returns the output of the command if no Exception.
+    """
+    attempt, finished, limit = 0, False, self.timeout
+
+    while not finished:
+      try:
+        attempt += 1
+        result = self.try_command()
+        finished = True
+        return result
+      except CmdTimedOut:
+        if attempt != ntries:
+          self.notify_retry()
+          self.timeout += limit
+        else:
+          raise
+
+  def notify_retry(self):
+    """ Retry required for command, notify user. """
+    for count in range(3, 0, -1):
+      if G_STOP.is_set():
+        raise KeyboardInterrupt
+      msg = 'Timeout. Will retry in {0} second{1} ...'.format(
+            count, 's' if count != 1 else '')
+      self.callback([msg])
+      time.sleep(1)
+    self.callback(['Retrying ...'])
+
+  def try_command(self):
+    """ Execute a cmd & poll for callback. Returns list of output.
+        Raises CmdFailed   -> return code for Popen isn't 0
+        Raises CmdTimedOut -> command exceeded timeout without new output
+    """
+    first_line = True
+
+    try:
+      tfile = tempfile.NamedTemporaryFile(mode='w+b')
+      preexec_fn = not G_IS_WIN and os.setsid or None
+      self.proc = subprocess.Popen(self.cmd, stdout=tfile,
+                                   stderr=subprocess.STDOUT,
+                                   stdin=subprocess.PIPE, shell=True,
+                                   preexec_fn=preexec_fn)
+      thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,))
+      thrd.start()
+
+      thread_not_started = True
+      while thread_not_started:
+        try:
+          thrd.join(0.1)
+          thread_not_started = False
+        except RuntimeError:
+          pass
+
+      while self.alive:
+        if G_STOP.is_set():
+          raise KeyboardInterrupt
+
+        if first_line or random.random() < G_LOG_PROB:
+          first_line = False
+          line = '' if G_IS_WIN else nonblock_read(tfile.name)
+          if line:
+            self.callback([line])
+
+        time_diff = time.time() - os.path.getmtime(tfile.name)
+        if time_diff > self.timeout:
+          raise CmdTimedOut(['Timeout!'])
+
+        thrd.join(0.5)
+
+      tfile.seek(0)
+      result = [line.decode('utf-8', 'replace').rstrip() for line in tfile]
+
+      if self.proc.returncode != 0:
+        raise CmdFailed([''] + result)
+
+      return result
+    except:
+      self.terminate()
+      raise
+
+  def terminate(self):
+    """ Terminate process and cleanup. """
+    if self.alive:
+      if G_IS_WIN:
+        os.kill(self.proc.pid, signal.SIGINT)
+      else:
+        os.killpg(self.proc.pid, signal.SIGTERM)
+    self.clean()
+
+class Plugin(object):
+  def __init__(self, name, args, buf_q, lock):
+    self.name = name
+    self.args = args
+    self.buf_q = buf_q
+    self.lock = lock
+    self.tag = args.get('tag', 0)
+
+  def manage(self):
+    try:
+      if os.path.exists(self.args['dir']):
+        self.update()
+      else:
+        self.install()
+        with self.lock:
+          thread_vim_command("let s:update.new['{0}'] = 1".format(self.name))
+    except PlugError as exc:
+      self.write(Action.ERROR, self.name, exc.msg)
+    except KeyboardInterrupt:
+      G_STOP.set()
+      self.write(Action.ERROR, self.name, ['Interrupted!'])
+    except:
+      # Any exception except those above print stack trace
+      msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip())
+      self.write(Action.ERROR, self.name, msg.split('\n'))
+      raise
+
+  def install(self):
+    target = self.args['dir']
+    if target[-1] == '\\':
+      target = target[0:-1]
+
+    def clean(target):
+      def _clean():
+        try:
+          shutil.rmtree(target)
+        except OSError:
+          pass
+      return _clean
+
+    self.write(Action.INSTALL, self.name, ['Installing ...'])
+    callback = functools.partial(self.write, Action.INSTALL, self.name)
+    cmd = 'git clone {0} {1} {2} {3} 2>&1'.format(
+          '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'],
+          esc(target))
+    com = Command(cmd, None, G_TIMEOUT, callback, clean(target))
+    result = com.execute(G_RETRIES)
+    self.write(Action.DONE, self.name, result[-1:])
+
+  def repo_uri(self):
+    cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url'
+    command = Command(cmd, self.args['dir'], G_TIMEOUT,)
+    result = command.execute(G_RETRIES)
+    return result[-1]
+
+  def update(self):
+    actual_uri = self.repo_uri()
+    expect_uri = self.args['uri']
+    regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$')
+    ma = regex.match(actual_uri)
+    mb = regex.match(expect_uri)
+    if ma is None or mb is None or ma.groups() != mb.groups():
+      msg = ['',
+             'Invalid URI: {0}'.format(actual_uri),
+             'Expected     {0}'.format(expect_uri),
+             'PlugClean required.']
+      raise InvalidURI(msg)
+
+    if G_PULL:
+      self.write(Action.UPDATE, self.name, ['Updating ...'])
+      callback = functools.partial(self.write, Action.UPDATE, self.name)
+      fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else ''
+      cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS)
+      com = Command(cmd, self.args['dir'], G_TIMEOUT, callback)
+      result = com.execute(G_RETRIES)
+      self.write(Action.DONE, self.name, result[-1:])
+    else:
+      self.write(Action.DONE, self.name, ['Already installed'])
+
+  def write(self, action, name, msg):
+    self.buf_q.put((action, name, msg))
+
+class PlugThread(thr.Thread):
+  def __init__(self, tname, args):
+    super(PlugThread, self).__init__()
+    self.tname = tname
+    self.args = args
+
+  def run(self):
+    thr.current_thread().name = self.tname
+    buf_q, work_q, lock = self.args
+
+    try:
+      while not G_STOP.is_set():
+        name, args = work_q.get_nowait()
+        plug = Plugin(name, args, buf_q, lock)
+        plug.manage()
+        work_q.task_done()
+    except queue.Empty:
+      pass
+
+class RefreshThread(thr.Thread):
+  def __init__(self, lock):
+    super(RefreshThread, self).__init__()
+    self.lock = lock
+    self.running = True
+
+  def run(self):
+    while self.running:
+      with self.lock:
+        thread_vim_command('noautocmd normal! a')
+      time.sleep(0.33)
+
+  def stop(self):
+    self.running = False
+
+if G_NVIM:
+  def thread_vim_command(cmd):
+    vim.session.threadsafe_call(lambda: vim.command(cmd))
+else:
+  def thread_vim_command(cmd):
+    vim.command(cmd)
+
+def esc(name):
+  return '"' + name.replace('"', '\"') + '"'
+
+def nonblock_read(fname):
+  """ Read a file with nonblock flag. Return the last line. """
+  fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK)
+  buf = os.read(fread, 100000).decode('utf-8', 'replace')
+  os.close(fread)
+
+  line = buf.rstrip('\r\n')
+  left = max(line.rfind('\r'), line.rfind('\n'))
+  if left != -1:
+    left += 1
+    line = line[left:]
+
+  return line
+
+def main():
+  thr.current_thread().name = 'main'
+  nthreads = int(vim.eval('s:update.threads'))
+  plugs = vim.eval('s:update.todo')
+  mac_gui = vim.eval('s:mac_gui') == '1'
+
+  lock = thr.Lock()
+  buf = Buffer(lock, len(plugs), G_PULL)
+  buf_q, work_q = queue.Queue(), queue.Queue()
+  for work in plugs.items():
+    work_q.put(work)
+
+  start_cnt = thr.active_count()
+  for num in range(nthreads):
+    tname = 'PlugT-{0:02}'.format(num)
+    thread = PlugThread(tname, (buf_q, work_q, lock))
+    thread.start()
+  if mac_gui:
+    rthread = RefreshThread(lock)
+    rthread.start()
+
+  while not buf_q.empty() or thr.active_count() != start_cnt:
+    try:
+      action, name, msg = buf_q.get(True, 0.25)
+      buf.write(action, name, ['OK'] if not msg else msg)
+      buf_q.task_done()
+    except queue.Empty:
+      pass
+    except KeyboardInterrupt:
+      G_STOP.set()
+
+  if mac_gui:
+    rthread.stop()
+    rthread.join()
+
+main()
+EOF
+endfunction
+
+function! s:update_ruby()
+  ruby << EOF
+  module PlugStream
+    SEP = ["\r", "\n", nil]
+    def get_line
+      buffer = ''
+      loop do
+        char = readchar rescue return
+        if SEP.include? char.chr
+          buffer << $/
+          break
+        else
+          buffer << char
+        end
+      end
+      buffer
+    end
+  end unless defined?(PlugStream)
+
+  def esc arg
+    %["#{arg.gsub('"', '\"')}"]
+  end
+
+  def killall pid
+    pids = [pid]
+    if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM
+      pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil }
+    else
+      unless `which pgrep 2> /dev/null`.empty?
+        children = pids
+        until children.empty?
+          children = children.map { |pid|
+            `pgrep -P #{pid}`.lines.map { |l| l.chomp }
+          }.flatten
+          pids += children
+        end
+      end
+      pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
+    end
+  end
+
+  def compare_git_uri a, b
+    regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$}
+    regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1)
+  end
+
+  require 'thread'
+  require 'fileutils'
+  require 'timeout'
+  running = true
+  iswin = VIM::evaluate('s:is_win').to_i == 1
+  pull  = VIM::evaluate('s:update.pull').to_i == 1
+  base  = VIM::evaluate('g:plug_home')
+  all   = VIM::evaluate('s:update.todo')
+  limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
+  tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1
+  nthr  = VIM::evaluate('s:update.threads').to_i
+  maxy  = VIM::evaluate('winheight(".")').to_i
+  vim7  = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/
+  cd    = iswin ? 'cd /d' : 'cd'
+  tot   = VIM::evaluate('len(s:update.todo)') || 0
+  bar   = ''
+  skip  = 'Already installed'
+  mtx   = Mutex.new
+  take1 = proc { mtx.synchronize { running && all.shift } }
+  logh  = proc {
+    cnt = bar.length
+    $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
+    $curbuf[2] = '[' + bar.ljust(tot) + ']'
+    VIM::command('normal! 2G')
+    VIM::command('redraw')
+  }
+  where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } }
+  log   = proc { |name, result, type|
+    mtx.synchronize do
+      ing  = ![true, false].include?(type)
+      bar += type ? '=' : 'x' unless ing
+      b = case type
+          when :install  then '+' when :update then '*'
+          when true, nil then '-' else
+            VIM::command("call add(s:update.errors, '#{name}')")
+            'x'
+          end
+      result =
+        if type || type.nil?
+          ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"]
+        elsif result =~ /^Interrupted|^Timeout/
+          ["#{b} #{name}: #{result}"]
+        else
+          ["#{b} #{name}"] + result.lines.map { |l| "    " << l }
+        end
+      if lnum = where.call(name)
+        $curbuf.delete lnum
+        lnum = 4 if ing && lnum > maxy
+      end
+      result.each_with_index do |line, offset|
+        $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp)
+      end
+      logh.call
+    end
+  }
+  bt = proc { |cmd, name, type, cleanup|
+    tried = timeout = 0
+    begin
+      tried += 1
+      timeout += limit
+      fd = nil
+      data = ''
+      if iswin
+        Timeout::timeout(timeout) do
+          tmp = VIM::evaluate('tempname()')
+          system("(#{cmd}) > #{tmp}")
+          data = File.read(tmp).chomp
+          File.unlink tmp rescue nil
+        end
+      else
+        fd = IO.popen(cmd).extend(PlugStream)
+        first_line = true
+        log_prob = 1.0 / nthr
+        while line = Timeout::timeout(timeout) { fd.get_line }
+          data << line
+          log.call name, line.chomp, type if name && (first_line || rand < log_prob)
+          first_line = false
+        end
+        fd.close
+      end
+      [$? == 0, data.chomp]
+    rescue Timeout::Error, Interrupt => e
+      if fd && !fd.closed?
+        killall fd.pid
+        fd.close
+      end
+      cleanup.call if cleanup
+      if e.is_a?(Timeout::Error) && tried < tries
+        3.downto(1) do |countdown|
+          s = countdown > 1 ? 's' : ''
+          log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type
+          sleep 1
+        end
+        log.call name, 'Retrying ...', type
+        retry
+      end
+      [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
+    end
+  }
+  main = Thread.current
+  threads = []
+  watcher = Thread.new {
+    if vim7
+      while VIM::evaluate('getchar(1)')
+        sleep 0.1
+      end
+    else
+      require 'io/console' # >= Ruby 1.9
+      nil until IO.console.getch == 3.chr
+    end
+    mtx.synchronize do
+      running = false
+      threads.each { |t| t.raise Interrupt } unless vim7
+    end
+    threads.each { |t| t.join rescue nil }
+    main.kill
+  }
+  refresh = Thread.new {
+    while true
+      mtx.synchronize do
+        break unless running
+        VIM::command('noautocmd normal! a')
+      end
+      sleep 0.2
+    end
+  } if VIM::evaluate('s:mac_gui') == 1
+
+  clone_opt = VIM::evaluate('s:clone_opt').join(' ')
+  progress = VIM::evaluate('s:progress_opt(1)')
+  nthr.times do
+    mtx.synchronize do
+      threads << Thread.new {
+        while pair = take1.call
+          name = pair.first
+          dir, uri, tag = pair.last.values_at *%w[dir uri tag]
+          exists = File.directory? dir
+          ok, result =
+            if exists
+              chdir = "#{cd} #{iswin ? dir : esc(dir)}"
+              ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil
+              current_uri = data.lines.to_a.last
+              if !ret
+                if data =~ /^Interrupted|^Timeout/
+                  [false, data]
+                else
+                  [false, [data.chomp, "PlugClean required."].join($/)]
+                end
+              elsif !compare_git_uri(current_uri, uri)
+                [false, ["Invalid URI: #{current_uri}",
+                         "Expected:    #{uri}",
+                         "PlugClean required."].join($/)]
+              else
+                if pull
+                  log.call name, 'Updating ...', :update
+                  fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : ''
+                  bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil
+                else
+                  [true, skip]
+                end
+              end
+            else
+              d = esc dir.sub(%r{[\\/]+$}, '')
+              log.call name, 'Installing ...', :install
+              bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc {
+                FileUtils.rm_rf dir
+              }
+            end
+          mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok
+          log.call name, result, ok
+        end
+      } if running
+    end
+  end
+  threads.each { |t| t.join rescue nil }
+  logh.call
+  refresh.kill if refresh
+  watcher.kill
+EOF
+endfunction
+
+function! s:shellesc_cmd(arg, script)
+  let escaped = substitute('"'.a:arg.'"', '[&|<>()@^!"]', '^&', 'g')
+  return substitute(escaped, '%', (a:script ? '%' : '^') . '&', 'g')
+endfunction
+
+function! s:shellesc_ps1(arg)
+  return "'".substitute(escape(a:arg, '\"'), "'", "''", 'g')."'"
+endfunction
+
+function! s:shellesc_sh(arg)
+  return "'".substitute(a:arg, "'", "'\\\\''", 'g')."'"
+endfunction
+
+" Escape the shell argument based on the shell.
+" Vim and Neovim's shellescape() are insufficient.
+" 1. shellslash determines whether to use single/double quotes.
+"    Double-quote escaping is fragile for cmd.exe.
+" 2. It does not work for powershell.
+" 3. It does not work for *sh shells if the command is executed
+"    via cmd.exe (ie. cmd.exe /c sh -c command command_args)
+" 4. It does not support batchfile syntax.
+"
+" Accepts an optional dictionary with the following keys:
+" - shell: same as Vim/Neovim 'shell' option.
+"          If unset, fallback to 'cmd.exe' on Windows or 'sh'.
+" - script: If truthy and shell is cmd.exe, escape for batchfile syntax.
+function! plug#shellescape(arg, ...)
+  if a:arg =~# '^[A-Za-z0-9_/:.-]\+$'
+    return a:arg
+  endif
+  let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {}
+  let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh')
+  let script = get(opts, 'script', 1)
+  if shell =~# 'cmd\(\.exe\)\?$'
+    return s:shellesc_cmd(a:arg, script)
+  elseif shell =~# 'powershell\(\.exe\)\?$' || shell =~# 'pwsh$'
+    return s:shellesc_ps1(a:arg)
+  endif
+  return s:shellesc_sh(a:arg)
+endfunction
+
+function! s:glob_dir(path)
+  return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)')
+endfunction
+
+function! s:progress_bar(line, bar, total)
+  call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']')
+endfunction
+
+function! s:compare_git_uri(a, b)
+  " See `git help clone'
+  " https:// [user@] github.com[:port] / junegunn/vim-plug [.git]
+  "          [git@]  github.com[:port] : junegunn/vim-plug [.git]
+  " file://                            / junegunn/vim-plug        [/]
+  "                                    / junegunn/vim-plug        [/]
+  let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$'
+  let ma = matchlist(a:a, pat)
+  let mb = matchlist(a:b, pat)
+  return ma[1:2] ==# mb[1:2]
+endfunction
+
+function! s:format_message(bullet, name, message)
+  if a:bullet != 'x'
+    return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))]
+  else
+    let lines = map(s:lines(a:message), '"    ".v:val')
+    return extend([printf('x %s:', a:name)], lines)
+  endif
+endfunction
+
+function! s:with_cd(cmd, dir, ...)
+  let script = a:0 > 0 ? a:1 : 1
+  return printf('cd%s %s && %s', s:is_win ? ' /d' : '', plug#shellescape(a:dir, {'script': script}), a:cmd)
+endfunction
+
+function! s:system(cmd, ...)
+  let batchfile = ''
+  try
+    let [sh, shellcmdflag, shrd] = s:chsh(1)
+    if type(a:cmd) == s:TYPE.list
+      " Neovim's system() supports list argument to bypass the shell
+      " but it cannot set the working directory for the command.
+      " Assume that the command does not rely on the shell.
+      if has('nvim') && a:0 == 0
+        return system(a:cmd)
+      endif
+      let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})'))
+      if &shell =~# 'powershell\(\.exe\)\?$'
+        let cmd = '& ' . cmd
+      endif
+    else
+      let cmd = a:cmd
+    endif
+    if a:0 > 0
+      let cmd = s:with_cd(cmd, a:1, type(a:cmd) != s:TYPE.list)
+    endif
+    if s:is_win && type(a:cmd) != s:TYPE.list
+      let [batchfile, cmd] = s:batchfile(cmd)
+    endif
+    return system(cmd)
+  finally
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win && filereadable(batchfile)
+      call delete(batchfile)
+    endif
+  endtry
+endfunction
+
+function! s:system_chomp(...)
+  let ret = call('s:system', a:000)
+  return v:shell_error ? '' : substitute(ret, '\n$', '', '')
+endfunction
+
+function! s:git_validate(spec, check_branch)
+  let err = ''
+  if isdirectory(a:spec.dir)
+    let result = [s:git_local_branch(a:spec.dir), s:git_origin_url(a:spec.dir)]
+    let remote = result[-1]
+    if empty(remote)
+      let err = join([remote, 'PlugClean required.'], "\n")
+    elseif !s:compare_git_uri(remote, a:spec.uri)
+      let err = join(['Invalid URI: '.remote,
+                    \ 'Expected:    '.a:spec.uri,
+                    \ 'PlugClean required.'], "\n")
+    elseif a:check_branch && has_key(a:spec, 'commit')
+      let sha = s:git_revision(a:spec.dir)
+      if empty(sha)
+        let err = join(add(result, 'PlugClean required.'), "\n")
+      elseif !s:hash_match(sha, a:spec.commit)
+        let err = join([printf('Invalid HEAD (expected: %s, actual: %s)',
+                              \ a:spec.commit[:6], sha[:6]),
+                      \ 'PlugUpdate required.'], "\n")
+      endif
+    elseif a:check_branch
+      let current_branch = result[0]
+      " Check tag
+      let origin_branch = s:git_origin_branch(a:spec)
+      if has_key(a:spec, 'tag')
+        let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)
+        if a:spec.tag !=# tag && a:spec.tag !~ '\*'
+          let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.',
+                \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
+        endif
+      " Check branch
+      elseif origin_branch !=# current_branch
+        let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',
+              \ current_branch, origin_branch)
+      endif
+      if empty(err)
+        let [ahead, behind] = split(s:lastline(s:system([
+        \ 'git', 'rev-list', '--count', '--left-right',
+        \ printf('HEAD...origin/%s', origin_branch)
+        \ ], a:spec.dir)), '\t')
+        if !v:shell_error && ahead
+          if behind
+            " Only mention PlugClean if diverged, otherwise it's likely to be
+            " pushable (and probably not that messed up).
+            let err = printf(
+                  \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n"
+                  \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', origin_branch, ahead, behind)
+          else
+            let err = printf("Ahead of origin/%s by %d commit(s).\n"
+                  \ .'Cannot update until local changes are pushed.',
+                  \ origin_branch, ahead)
+          endif
+        endif
+      endif
+    endif
+  else
+    let err = 'Not found'
+  endif
+  return [err, err =~# 'PlugClean']
+endfunction
+
+function! s:rm_rf(dir)
+  if isdirectory(a:dir)
+    return s:system(s:is_win
+    \ ? 'rmdir /S /Q '.plug#shellescape(a:dir)
+    \ : ['rm', '-rf', a:dir])
+  endif
+endfunction
+
+function! s:clean(force)
+  call s:prepare()
+  call append(0, 'Searching for invalid plugins in '.g:plug_home)
+  call append(1, '')
+
+  " List of valid directories
+  let dirs = []
+  let errs = {}
+  let [cnt, total] = [0, len(g:plugs)]
+  for [name, spec] in items(g:plugs)
+    if !s:is_managed(name)
+      call add(dirs, spec.dir)
+    else
+      let [err, clean] = s:git_validate(spec, 1)
+      if clean
+        let errs[spec.dir] = s:lines(err)[0]
+      else
+        call add(dirs, spec.dir)
+      endif
+    endif
+    let cnt += 1
+    call s:progress_bar(2, repeat('=', cnt), total)
+    normal! 2G
+    redraw
+  endfor
+
+  let allowed = {}
+  for dir in dirs
+    let allowed[s:dirpath(s:plug_fnamemodify(dir, ':h:h'))] = 1
+    let allowed[dir] = 1
+    for child in s:glob_dir(dir)
+      let allowed[child] = 1
+    endfor
+  endfor
+
+  let todo = []
+  let found = sort(s:glob_dir(g:plug_home))
+  while !empty(found)
+    let f = remove(found, 0)
+    if !has_key(allowed, f) && isdirectory(f)
+      call add(todo, f)
+      call append(line('$'), '- ' . f)
+      if has_key(errs, f)
+        call append(line('$'), '    ' . errs[f])
+      endif
+      let found = filter(found, 'stridx(v:val, f) != 0')
+    end
+  endwhile
+
+  4
+  redraw
+  if empty(todo)
+    call append(line('$'), 'Already clean.')
+  else
+    let s:clean_count = 0
+    call append(3, ['Directories to delete:', ''])
+    redraw!
+    if a:force || s:ask_no_interrupt('Delete all directories?')
+      call s:delete([6, line('$')], 1)
+    else
+      call setline(4, 'Cancelled.')
+      nnoremap <silent> <buffer> d :set opfunc=<sid>delete_op<cr>g@
+      nmap     <silent> <buffer> dd d_
+      xnoremap <silent> <buffer> d :<c-u>call <sid>delete_op(visualmode(), 1)<cr>
+      echo 'Delete the lines (d{motion}) to delete the corresponding directories'
+    endif
+  endif
+  4
+  setlocal nomodifiable
+endfunction
+
+function! s:delete_op(type, ...)
+  call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0)
+endfunction
+
+function! s:delete(range, force)
+  let [l1, l2] = a:range
+  let force = a:force
+  let err_count = 0
+  while l1 <= l2
+    let line = getline(l1)
+    if line =~ '^- ' && isdirectory(line[2:])
+      execute l1
+      redraw!
+      let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1)
+      let force = force || answer > 1
+      if answer
+        let err = s:rm_rf(line[2:])
+        setlocal modifiable
+        if empty(err)
+          call setline(l1, '~'.line[1:])
+          let s:clean_count += 1
+        else
+          delete _
+          call append(l1 - 1, s:format_message('x', line[1:], err))
+          let l2 += len(s:lines(err))
+          let err_count += 1
+        endif
+        let msg = printf('Removed %d directories.', s:clean_count)
+        if err_count > 0
+          let msg .= printf(' Failed to remove %d directories.', err_count)
+        endif
+        call setline(4, msg)
+        setlocal nomodifiable
+      endif
+    endif
+    let l1 += 1
+  endwhile
+endfunction
+
+function! s:upgrade()
+  echo 'Downloading the latest version of vim-plug'
+  redraw
+  let tmp = s:plug_tempname()
+  let new = tmp . '/plug.vim'
+
+  try
+    let out = s:system(['git', 'clone', '--depth', '1', s:plug_src, tmp])
+    if v:shell_error
+      return s:err('Error upgrading vim-plug: '. out)
+    endif
+
+    if readfile(s:me) ==# readfile(new)
+      echo 'vim-plug is already up-to-date'
+      return 0
+    else
+      call rename(s:me, s:me . '.old')
+      call rename(new, s:me)
+      unlet g:loaded_plug
+      echo 'vim-plug has been upgraded'
+      return 1
+    endif
+  finally
+    silent! call s:rm_rf(tmp)
+  endtry
+endfunction
+
+function! s:upgrade_specs()
+  for spec in values(g:plugs)
+    let spec.frozen = get(spec, 'frozen', 0)
+  endfor
+endfunction
+
+function! s:status()
+  call s:prepare()
+  call append(0, 'Checking plugins')
+  call append(1, '')
+
+  let ecnt = 0
+  let unloaded = 0
+  let [cnt, total] = [0, len(g:plugs)]
+  for [name, spec] in items(g:plugs)
+    let is_dir = isdirectory(spec.dir)
+    if has_key(spec, 'uri')
+      if is_dir
+        let [err, _] = s:git_validate(spec, 1)
+        let [valid, msg] = [empty(err), empty(err) ? 'OK' : err]
+      else
+        let [valid, msg] = [0, 'Not found. Try PlugInstall.']
+      endif
+    else
+      if is_dir
+        let [valid, msg] = [1, 'OK']
+      else
+        let [valid, msg] = [0, 'Not found.']
+      endif
+    endif
+    let cnt += 1
+    let ecnt += !valid
+    " `s:loaded` entry can be missing if PlugUpgraded
+    if is_dir && get(s:loaded, name, -1) == 0
+      let unloaded = 1
+      let msg .= ' (not loaded)'
+    endif
+    call s:progress_bar(2, repeat('=', cnt), total)
+    call append(3, s:format_message(valid ? '-' : 'x', name, msg))
+    normal! 2G
+    redraw
+  endfor
+  call setline(1, 'Finished. '.ecnt.' error(s).')
+  normal! gg
+  setlocal nomodifiable
+  if unloaded
+    echo "Press 'L' on each line to load plugin, or 'U' to update"
+    nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
+    xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
+  end
+endfunction
+
+function! s:extract_name(str, prefix, suffix)
+  return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$')
+endfunction
+
+function! s:status_load(lnum)
+  let line = getline(a:lnum)
+  let name = s:extract_name(line, '-', '(not loaded)')
+  if !empty(name)
+    call plug#load(name)
+    setlocal modifiable
+    call setline(a:lnum, substitute(line, ' (not loaded)$', '', ''))
+    setlocal nomodifiable
+  endif
+endfunction
+
+function! s:status_update() range
+  let lines = getline(a:firstline, a:lastline)
+  let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)')
+  if !empty(names)
+    echo
+    execute 'PlugUpdate' join(names)
+  endif
+endfunction
+
+function! s:is_preview_window_open()
+  silent! wincmd P
+  if &previewwindow
+    wincmd p
+    return 1
+  endif
+endfunction
+
+function! s:find_name(lnum)
+  for lnum in reverse(range(1, a:lnum))
+    let line = getline(lnum)
+    if empty(line)
+      return ''
+    endif
+    let name = s:extract_name(line, '-', '')
+    if !empty(name)
+      return name
+    endif
+  endfor
+  return ''
+endfunction
+
+function! s:preview_commit()
+  if b:plug_preview < 0
+    let b:plug_preview = !s:is_preview_window_open()
+  endif
+
+  let sha = matchstr(getline('.'), '^  \X*\zs[0-9a-f]\{7,9}')
+  if empty(sha)
+    return
+  endif
+
+  let name = s:find_name(line('.'))
+  if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir)
+    return
+  endif
+
+  if exists('g:plug_pwindow') && !s:is_preview_window_open()
+    execute g:plug_pwindow
+    execute 'e' sha
+  else
+    execute 'pedit' sha
+    wincmd P
+  endif
+  setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable
+  let batchfile = ''
+  try
+    let [sh, shellcmdflag, shrd] = s:chsh(1)
+    let cmd = 'cd '.plug#shellescape(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha
+    if s:is_win
+      let [batchfile, cmd] = s:batchfile(cmd)
+    endif
+    execute 'silent %!' cmd
+  finally
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win && filereadable(batchfile)
+      call delete(batchfile)
+    endif
+  endtry
+  setlocal nomodifiable
+  nnoremap <silent> <buffer> q :q<cr>
+  wincmd p
+endfunction
+
+function! s:section(flags)
+  call search('\(^[x-] \)\@<=[^:]\+:', a:flags)
+endfunction
+
+function! s:format_git_log(line)
+  let indent = '  '
+  let tokens = split(a:line, nr2char(1))
+  if len(tokens) != 5
+    return indent.substitute(a:line, '\s*$', '', '')
+  endif
+  let [graph, sha, refs, subject, date] = tokens
+  let tag = matchstr(refs, 'tag: [^,)]\+')
+  let tag = empty(tag) ? ' ' : ' ('.tag.') '
+  return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date)
+endfunction
+
+function! s:append_ul(lnum, text)
+  call append(a:lnum, ['', a:text, repeat('-', len(a:text))])
+endfunction
+
+function! s:diff()
+  call s:prepare()
+  call append(0, ['Collecting changes ...', ''])
+  let cnts = [0, 0]
+  let bar = ''
+  let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)')
+  call s:progress_bar(2, bar, len(total))
+  for origin in [1, 0]
+    let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))'))))
+    if empty(plugs)
+      continue
+    endif
+    call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')
+    for [k, v] in plugs
+      let branch = s:git_origin_branch(v)
+      if len(branch)
+        let range = origin ? '..origin/'.branch : 'HEAD@{1}..'
+        let cmd = ['git', 'log', '--graph', '--color=never']
+        if s:git_version_requirement(2, 10, 0)
+          call add(cmd, '--no-show-signature')
+        endif
+        call extend(cmd, ['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range])
+        if has_key(v, 'rtp')
+          call extend(cmd, ['--', v.rtp])
+        endif
+        let diff = s:system_chomp(cmd, v.dir)
+        if !empty(diff)
+          let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''
+          call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))
+          let cnts[origin] += 1
+        endif
+      endif
+      let bar .= '='
+      call s:progress_bar(2, bar, len(total))
+      normal! 2G
+      redraw
+    endfor
+    if !cnts[origin]
+      call append(5, ['', 'N/A'])
+    endif
+  endfor
+  call setline(1, printf('%d plugin(s) updated.', cnts[0])
+        \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : ''))
+
+  if cnts[0] || cnts[1]
+    nnoremap <silent> <buffer> <plug>(plug-preview) :silent! call <SID>preview_commit()<cr>
+    if empty(maparg("\<cr>", 'n'))
+      nmap <buffer> <cr> <plug>(plug-preview)
+    endif
+    if empty(maparg('o', 'n'))
+      nmap <buffer> o <plug>(plug-preview)
+    endif
+  endif
+  if cnts[0]
+    nnoremap <silent> <buffer> X :call <SID>revert()<cr>
+    echo "Press 'X' on each block to revert the update"
+  endif
+  normal! gg
+  setlocal nomodifiable
+endfunction
+
+function! s:revert()
+  if search('^Pending updates', 'bnW')
+    return
+  endif
+
+  let name = s:find_name(line('.'))
+  if empty(name) || !has_key(g:plugs, name) ||
+    \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y'
+    return
+  endif
+
+  call s:system('git reset --hard HEAD@{1} && git checkout '.plug#shellescape(g:plugs[name].branch).' --', g:plugs[name].dir)
+  setlocal modifiable
+  normal! "_dap
+  setlocal nomodifiable
+  echo 'Reverted'
+endfunction
+
+function! s:snapshot(force, ...) abort
+  call s:prepare()
+  setf vim
+  call append(0, ['" Generated by vim-plug',
+                \ '" '.strftime("%c"),
+                \ '" :source this file in vim to restore the snapshot',
+                \ '" or execute: vim -S snapshot.vim',
+                \ '', '', 'PlugUpdate!'])
+  1
+  let anchor = line('$') - 3
+  let names = sort(keys(filter(copy(g:plugs),
+        \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)')))
+  for name in reverse(names)
+    let sha = s:git_revision(g:plugs[name].dir)
+    if !empty(sha)
+      call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha))
+      redraw
+    endif
+  endfor
+
+  if a:0 > 0
+    let fn = s:plug_expand(a:1)
+    if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?'))
+      return
+    endif
+    call writefile(getline(1, '$'), fn)
+    echo 'Saved as '.a:1
+    silent execute 'e' s:esc(fn)
+    setf vim
+  endif
+endfunction
+
+function! s:split_rtp()
+  return split(&rtp, '\\\@<!,')
+endfunction
+
+let s:first_rtp = s:escrtp(get(s:split_rtp(), 0, ''))
+let s:last_rtp  = s:escrtp(get(s:split_rtp(), -1, ''))
+
+if exists('g:plugs')
+  let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs))
+  call s:upgrade_specs()
+  call s:define_commands()
+endif
+
+let &cpo = s:cpo_save
+unlet s:cpo_save

+ 2788 - 0
dot-config/vim/plug.vim

@@ -0,0 +1,2788 @@
+" vim-plug: Vim plugin manager
+" ============================
+"
+" Download plug.vim and put it in ~/.vim/autoload
+"
+"   curl -fLo ~/.vim/autoload/plug.vim --create-dirs \
+"     https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
+"
+" Edit your .vimrc
+"
+"   call plug#begin('~/.vim/plugged')
+"
+"   " Make sure you use single quotes
+"
+"   " Shorthand notation; fetches https://github.com/junegunn/vim-easy-align
+"   Plug 'junegunn/vim-easy-align'
+"
+"   " Any valid git URL is allowed
+"   Plug 'https://github.com/junegunn/vim-github-dashboard.git'
+"
+"   " Multiple Plug commands can be written in a single line using | separators
+"   Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets'
+"
+"   " On-demand loading
+"   Plug 'scrooloose/nerdtree', { 'on':  'NERDTreeToggle' }
+"   Plug 'tpope/vim-fireplace', { 'for': 'clojure' }
+"
+"   " Using a non-default branch
+"   Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }
+"
+"   " Using a tagged release; wildcard allowed (requires git 1.9.2 or above)
+"   Plug 'fatih/vim-go', { 'tag': '*' }
+"
+"   " Plugin options
+"   Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' }
+"
+"   " Plugin outside ~/.vim/plugged with post-update hook
+"   Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }
+"
+"   " Unmanaged plugin (manually installed and updated)
+"   Plug '~/my-prototype-plugin'
+"
+"   " Initialize plugin system
+"   call plug#end()
+"
+" Then reload .vimrc and :PlugInstall to install plugins.
+"
+" Plug options:
+"
+"| Option                  | Description                                      |
+"| ----------------------- | ------------------------------------------------ |
+"| `branch`/`tag`/`commit` | Branch/tag/commit of the repository to use       |
+"| `rtp`                   | Subdirectory that contains Vim plugin            |
+"| `dir`                   | Custom directory for the plugin                  |
+"| `as`                    | Use different name for the plugin                |
+"| `do`                    | Post-update hook (string or funcref)             |
+"| `on`                    | On-demand loading: Commands or `<Plug>`-mappings |
+"| `for`                   | On-demand loading: File types                    |
+"| `frozen`                | Do not update unless explicitly specified        |
+"
+" More information: https://github.com/junegunn/vim-plug
+"
+"
+" Copyright (c) 2017 Junegunn Choi
+"
+" MIT License
+"
+" Permission is hereby granted, free of charge, to any person obtaining
+" a copy of this software and associated documentation files (the
+" "Software"), to deal in the Software without restriction, including
+" without limitation the rights to use, copy, modify, merge, publish,
+" distribute, sublicense, and/or sell copies of the Software, and to
+" permit persons to whom the Software is furnished to do so, subject to
+" the following conditions:
+"
+" The above copyright notice and this permission notice shall be
+" included in all copies or substantial portions of the Software.
+"
+" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+if exists('g:loaded_plug')
+  finish
+endif
+let g:loaded_plug = 1
+
+let s:cpo_save = &cpo
+set cpo&vim
+
+let s:plug_src = 'https://github.com/junegunn/vim-plug.git'
+let s:plug_tab = get(s:, 'plug_tab', -1)
+let s:plug_buf = get(s:, 'plug_buf', -1)
+let s:mac_gui = has('gui_macvim') && has('gui_running')
+let s:is_win = has('win32')
+let s:nvim = has('nvim-0.2') || (has('nvim') && exists('*jobwait') && !s:is_win)
+let s:vim8 = has('patch-8.0.0039') && exists('*job_start')
+if s:is_win && &shellslash
+  set noshellslash
+  let s:me = resolve(expand('<sfile>:p'))
+  set shellslash
+else
+  let s:me = resolve(expand('<sfile>:p'))
+endif
+let s:base_spec = { 'branch': '', 'frozen': 0 }
+let s:TYPE = {
+\   'string':  type(''),
+\   'list':    type([]),
+\   'dict':    type({}),
+\   'funcref': type(function('call'))
+\ }
+let s:loaded = get(s:, 'loaded', {})
+let s:triggers = get(s:, 'triggers', {})
+
+function! s:isabsolute(dir) abort
+  return a:dir =~# '^/' || (has('win32') && a:dir =~? '^\%(\\\|[A-Z]:\)')
+endfunction
+
+function! s:git_dir(dir) abort
+  let gitdir = s:trim(a:dir) . '/.git'
+  if isdirectory(gitdir)
+    return gitdir
+  endif
+  if !filereadable(gitdir)
+    return ''
+  endif
+  let gitdir = matchstr(get(readfile(gitdir), 0, ''), '^gitdir: \zs.*')
+  if len(gitdir) && !s:isabsolute(gitdir)
+    let gitdir = a:dir . '/' . gitdir
+  endif
+  return isdirectory(gitdir) ? gitdir : ''
+endfunction
+
+function! s:git_origin_url(dir) abort
+  let gitdir = s:git_dir(a:dir)
+  let config = gitdir . '/config'
+  if empty(gitdir) || !filereadable(config)
+    return ''
+  endif
+  return matchstr(join(readfile(config)), '\[remote "origin"\].\{-}url\s*=\s*\zs\S*\ze')
+endfunction
+
+function! s:git_revision(dir) abort
+  let gitdir = s:git_dir(a:dir)
+  let head = gitdir . '/HEAD'
+  if empty(gitdir) || !filereadable(head)
+    return ''
+  endif
+
+  let line = get(readfile(head), 0, '')
+  let ref = matchstr(line, '^ref: \zs.*')
+  if empty(ref)
+    return line
+  endif
+
+  if filereadable(gitdir . '/' . ref)
+    return get(readfile(gitdir . '/' . ref), 0, '')
+  endif
+
+  if filereadable(gitdir . '/packed-refs')
+    for line in readfile(gitdir . '/packed-refs')
+      if line =~# ' ' . ref
+        return matchstr(line, '^[0-9a-f]*')
+      endif
+    endfor
+  endif
+
+  return ''
+endfunction
+
+function! s:git_local_branch(dir) abort
+  let gitdir = s:git_dir(a:dir)
+  let head = gitdir . '/HEAD'
+  if empty(gitdir) || !filereadable(head)
+    return ''
+  endif
+  let branch = matchstr(get(readfile(head), 0, ''), '^ref: refs/heads/\zs.*')
+  return len(branch) ? branch : 'HEAD'
+endfunction
+
+function! s:git_origin_branch(spec)
+  if len(a:spec.branch)
+    return a:spec.branch
+  endif
+
+  " The file may not be present if this is a local repository
+  let gitdir = s:git_dir(a:spec.dir)
+  let origin_head = gitdir.'/refs/remotes/origin/HEAD'
+  if len(gitdir) && filereadable(origin_head)
+    return matchstr(get(readfile(origin_head), 0, ''),
+                  \ '^ref: refs/remotes/origin/\zs.*')
+  endif
+
+  " The command may not return the name of a branch in detached HEAD state
+  let result = s:lines(s:system('git symbolic-ref --short HEAD', a:spec.dir))
+  return v:shell_error ? '' : result[-1]
+endfunction
+
+if s:is_win
+  function! s:plug_call(fn, ...)
+    let shellslash = &shellslash
+    try
+      set noshellslash
+      return call(a:fn, a:000)
+    finally
+      let &shellslash = shellslash
+    endtry
+  endfunction
+else
+  function! s:plug_call(fn, ...)
+    return call(a:fn, a:000)
+  endfunction
+endif
+
+function! s:plug_getcwd()
+  return s:plug_call('getcwd')
+endfunction
+
+function! s:plug_fnamemodify(fname, mods)
+  return s:plug_call('fnamemodify', a:fname, a:mods)
+endfunction
+
+function! s:plug_expand(fmt)
+  return s:plug_call('expand', a:fmt, 1)
+endfunction
+
+function! s:plug_tempname()
+  return s:plug_call('tempname')
+endfunction
+
+function! plug#begin(...)
+  if a:0 > 0
+    let s:plug_home_org = a:1
+    let home = s:path(s:plug_fnamemodify(s:plug_expand(a:1), ':p'))
+  elseif exists('g:plug_home')
+    let home = s:path(g:plug_home)
+  elseif !empty(&rtp)
+    let home = s:path(split(&rtp, ',')[0]) . '/plugged'
+  else
+    return s:err('Unable to determine plug home. Try calling plug#begin() with a path argument.')
+  endif
+  if s:plug_fnamemodify(home, ':t') ==# 'plugin' && s:plug_fnamemodify(home, ':h') ==# s:first_rtp
+    return s:err('Invalid plug home. '.home.' is a standard Vim runtime path and is not allowed.')
+  endif
+
+  let g:plug_home = home
+  let g:plugs = {}
+  let g:plugs_order = []
+  let s:triggers = {}
+
+  call s:define_commands()
+  return 1
+endfunction
+
+function! s:define_commands()
+  command! -nargs=+ -bar Plug call plug#(<args>)
+  if !executable('git')
+    return s:err('`git` executable not found. Most commands will not be available. To suppress this message, prepend `silent!` to `call plug#begin(...)`.')
+  endif
+  if has('win32')
+  \ && &shellslash
+  \ && (&shell =~# 'cmd\(\.exe\)\?$' || &shell =~# 'powershell\(\.exe\)\?$')
+    return s:err('vim-plug does not support shell, ' . &shell . ', when shellslash is set.')
+  endif
+  if !has('nvim')
+    \ && (has('win32') || has('win32unix'))
+    \ && !has('multi_byte')
+    return s:err('Vim needs +multi_byte feature on Windows to run shell commands. Enable +iconv for best results.')
+  endif
+  command! -nargs=* -bar -bang -complete=customlist,s:names PlugInstall call s:install(<bang>0, [<f-args>])
+  command! -nargs=* -bar -bang -complete=customlist,s:names PlugUpdate  call s:update(<bang>0, [<f-args>])
+  command! -nargs=0 -bar -bang PlugClean call s:clean(<bang>0)
+  command! -nargs=0 -bar PlugUpgrade if s:upgrade() | execute 'source' s:esc(s:me) | endif
+  command! -nargs=0 -bar PlugStatus  call s:status()
+  command! -nargs=0 -bar PlugDiff    call s:diff()
+  command! -nargs=? -bar -bang -complete=file PlugSnapshot call s:snapshot(<bang>0, <f-args>)
+endfunction
+
+function! s:to_a(v)
+  return type(a:v) == s:TYPE.list ? a:v : [a:v]
+endfunction
+
+function! s:to_s(v)
+  return type(a:v) == s:TYPE.string ? a:v : join(a:v, "\n") . "\n"
+endfunction
+
+function! s:glob(from, pattern)
+  return s:lines(globpath(a:from, a:pattern))
+endfunction
+
+function! s:source(from, ...)
+  let found = 0
+  for pattern in a:000
+    for vim in s:glob(a:from, pattern)
+      execute 'source' s:esc(vim)
+      let found = 1
+    endfor
+  endfor
+  return found
+endfunction
+
+function! s:assoc(dict, key, val)
+  let a:dict[a:key] = add(get(a:dict, a:key, []), a:val)
+endfunction
+
+function! s:ask(message, ...)
+  call inputsave()
+  echohl WarningMsg
+  let answer = input(a:message.(a:0 ? ' (y/N/a) ' : ' (y/N) '))
+  echohl None
+  call inputrestore()
+  echo "\r"
+  return (a:0 && answer =~? '^a') ? 2 : (answer =~? '^y') ? 1 : 0
+endfunction
+
+function! s:ask_no_interrupt(...)
+  try
+    return call('s:ask', a:000)
+  catch
+    return 0
+  endtry
+endfunction
+
+function! s:lazy(plug, opt)
+  return has_key(a:plug, a:opt) &&
+        \ (empty(s:to_a(a:plug[a:opt]))         ||
+        \  !isdirectory(a:plug.dir)             ||
+        \  len(s:glob(s:rtp(a:plug), 'plugin')) ||
+        \  len(s:glob(s:rtp(a:plug), 'after/plugin')))
+endfunction
+
+function! plug#end()
+  if !exists('g:plugs')
+    return s:err('plug#end() called without calling plug#begin() first')
+  endif
+
+  if exists('#PlugLOD')
+    augroup PlugLOD
+      autocmd!
+    augroup END
+    augroup! PlugLOD
+  endif
+  let lod = { 'ft': {}, 'map': {}, 'cmd': {} }
+
+  if exists('g:did_load_filetypes')
+    filetype off
+  endif
+  for name in g:plugs_order
+    if !has_key(g:plugs, name)
+      continue
+    endif
+    let plug = g:plugs[name]
+    if get(s:loaded, name, 0) || !s:lazy(plug, 'on') && !s:lazy(plug, 'for')
+      let s:loaded[name] = 1
+      continue
+    endif
+
+    if has_key(plug, 'on')
+      let s:triggers[name] = { 'map': [], 'cmd': [] }
+      for cmd in s:to_a(plug.on)
+        if cmd =~? '^<Plug>.\+'
+          if empty(mapcheck(cmd)) && empty(mapcheck(cmd, 'i'))
+            call s:assoc(lod.map, cmd, name)
+          endif
+          call add(s:triggers[name].map, cmd)
+        elseif cmd =~# '^[A-Z]'
+          let cmd = substitute(cmd, '!*$', '', '')
+          if exists(':'.cmd) != 2
+            call s:assoc(lod.cmd, cmd, name)
+          endif
+          call add(s:triggers[name].cmd, cmd)
+        else
+          call s:err('Invalid `on` option: '.cmd.
+          \ '. Should start with an uppercase letter or `<Plug>`.')
+        endif
+      endfor
+    endif
+
+    if has_key(plug, 'for')
+      let types = s:to_a(plug.for)
+      if !empty(types)
+        augroup filetypedetect
+        call s:source(s:rtp(plug), 'ftdetect/**/*.vim', 'after/ftdetect/**/*.vim')
+        augroup END
+      endif
+      for type in types
+        call s:assoc(lod.ft, type, name)
+      endfor
+    endif
+  endfor
+
+  for [cmd, names] in items(lod.cmd)
+    execute printf(
+    \ 'command! -nargs=* -range -bang -complete=file %s call s:lod_cmd(%s, "<bang>", <line1>, <line2>, <q-args>, %s)',
+    \ cmd, string(cmd), string(names))
+  endfor
+
+  for [map, names] in items(lod.map)
+    for [mode, map_prefix, key_prefix] in
+          \ [['i', '<C-O>', ''], ['n', '', ''], ['v', '', 'gv'], ['o', '', '']]
+      execute printf(
+      \ '%snoremap <silent> %s %s:<C-U>call <SID>lod_map(%s, %s, %s, "%s")<CR>',
+      \ mode, map, map_prefix, string(map), string(names), mode != 'i', key_prefix)
+    endfor
+  endfor
+
+  for [ft, names] in items(lod.ft)
+    augroup PlugLOD
+      execute printf('autocmd FileType %s call <SID>lod_ft(%s, %s)',
+            \ ft, string(ft), string(names))
+    augroup END
+  endfor
+
+  call s:reorg_rtp()
+  filetype plugin indent on
+  if has('vim_starting')
+    if has('syntax') && !exists('g:syntax_on')
+      syntax enable
+    end
+  else
+    call s:reload_plugins()
+  endif
+endfunction
+
+function! s:loaded_names()
+  return filter(copy(g:plugs_order), 'get(s:loaded, v:val, 0)')
+endfunction
+
+function! s:load_plugin(spec)
+  call s:source(s:rtp(a:spec), 'plugin/**/*.vim', 'after/plugin/**/*.vim')
+endfunction
+
+function! s:reload_plugins()
+  for name in s:loaded_names()
+    call s:load_plugin(g:plugs[name])
+  endfor
+endfunction
+
+function! s:trim(str)
+  return substitute(a:str, '[\/]\+$', '', '')
+endfunction
+
+function! s:version_requirement(val, min)
+  for idx in range(0, len(a:min) - 1)
+    let v = get(a:val, idx, 0)
+    if     v < a:min[idx] | return 0
+    elseif v > a:min[idx] | return 1
+    endif
+  endfor
+  return 1
+endfunction
+
+function! s:git_version_requirement(...)
+  if !exists('s:git_version')
+    let s:git_version = map(split(split(s:system(['git', '--version']))[2], '\.'), 'str2nr(v:val)')
+  endif
+  return s:version_requirement(s:git_version, a:000)
+endfunction
+
+function! s:progress_opt(base)
+  return a:base && !s:is_win &&
+        \ s:git_version_requirement(1, 7, 1) ? '--progress' : ''
+endfunction
+
+function! s:rtp(spec)
+  return s:path(a:spec.dir . get(a:spec, 'rtp', ''))
+endfunction
+
+if s:is_win
+  function! s:path(path)
+    return s:trim(substitute(a:path, '/', '\', 'g'))
+  endfunction
+
+  function! s:dirpath(path)
+    return s:path(a:path) . '\'
+  endfunction
+
+  function! s:is_local_plug(repo)
+    return a:repo =~? '^[a-z]:\|^[%~]'
+  endfunction
+
+  " Copied from fzf
+  function! s:wrap_cmds(cmds)
+    let cmds = [
+      \ '@echo off',
+      \ 'setlocal enabledelayedexpansion']
+    \ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds])
+    \ + ['endlocal']
+    if has('iconv')
+      if !exists('s:codepage')
+        let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0)
+      endif
+      return map(cmds, printf('iconv(v:val."\r", "%s", "cp%d")', &encoding, s:codepage))
+    endif
+    return map(cmds, 'v:val."\r"')
+  endfunction
+
+  function! s:batchfile(cmd)
+    let batchfile = s:plug_tempname().'.bat'
+    call writefile(s:wrap_cmds(a:cmd), batchfile)
+    let cmd = plug#shellescape(batchfile, {'shell': &shell, 'script': 0})
+    if &shell =~# 'powershell\(\.exe\)\?$'
+      let cmd = '& ' . cmd
+    endif
+    return [batchfile, cmd]
+  endfunction
+else
+  function! s:path(path)
+    return s:trim(a:path)
+  endfunction
+
+  function! s:dirpath(path)
+    return substitute(a:path, '[/\\]*$', '/', '')
+  endfunction
+
+  function! s:is_local_plug(repo)
+    return a:repo[0] =~ '[/$~]'
+  endfunction
+endif
+
+function! s:err(msg)
+  echohl ErrorMsg
+  echom '[vim-plug] '.a:msg
+  echohl None
+endfunction
+
+function! s:warn(cmd, msg)
+  echohl WarningMsg
+  execute a:cmd 'a:msg'
+  echohl None
+endfunction
+
+function! s:esc(path)
+  return escape(a:path, ' ')
+endfunction
+
+function! s:escrtp(path)
+  return escape(a:path, ' ,')
+endfunction
+
+function! s:remove_rtp()
+  for name in s:loaded_names()
+    let rtp = s:rtp(g:plugs[name])
+    execute 'set rtp-='.s:escrtp(rtp)
+    let after = globpath(rtp, 'after')
+    if isdirectory(after)
+      execute 'set rtp-='.s:escrtp(after)
+    endif
+  endfor
+endfunction
+
+function! s:reorg_rtp()
+  if !empty(s:first_rtp)
+    execute 'set rtp-='.s:first_rtp
+    execute 'set rtp-='.s:last_rtp
+  endif
+
+  " &rtp is modified from outside
+  if exists('s:prtp') && s:prtp !=# &rtp
+    call s:remove_rtp()
+    unlet! s:middle
+  endif
+
+  let s:middle = get(s:, 'middle', &rtp)
+  let rtps     = map(s:loaded_names(), 's:rtp(g:plugs[v:val])')
+  let afters   = filter(map(copy(rtps), 'globpath(v:val, "after")'), '!empty(v:val)')
+  let rtp      = join(map(rtps, 'escape(v:val, ",")'), ',')
+                 \ . ','.s:middle.','
+                 \ . join(map(afters, 'escape(v:val, ",")'), ',')
+  let &rtp     = substitute(substitute(rtp, ',,*', ',', 'g'), '^,\|,$', '', 'g')
+  let s:prtp   = &rtp
+
+  if !empty(s:first_rtp)
+    execute 'set rtp^='.s:first_rtp
+    execute 'set rtp+='.s:last_rtp
+  endif
+endfunction
+
+function! s:doautocmd(...)
+  if exists('#'.join(a:000, '#'))
+    execute 'doautocmd' ((v:version > 703 || has('patch442')) ? '<nomodeline>' : '') join(a:000)
+  endif
+endfunction
+
+function! s:dobufread(names)
+  for name in a:names
+    let path = s:rtp(g:plugs[name])
+    for dir in ['ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin']
+      if len(finddir(dir, path))
+        if exists('#BufRead')
+          doautocmd BufRead
+        endif
+        return
+      endif
+    endfor
+  endfor
+endfunction
+
+function! plug#load(...)
+  if a:0 == 0
+    return s:err('Argument missing: plugin name(s) required')
+  endif
+  if !exists('g:plugs')
+    return s:err('plug#begin was not called')
+  endif
+  let names = a:0 == 1 && type(a:1) == s:TYPE.list ? a:1 : a:000
+  let unknowns = filter(copy(names), '!has_key(g:plugs, v:val)')
+  if !empty(unknowns)
+    let s = len(unknowns) > 1 ? 's' : ''
+    return s:err(printf('Unknown plugin%s: %s', s, join(unknowns, ', ')))
+  end
+  let unloaded = filter(copy(names), '!get(s:loaded, v:val, 0)')
+  if !empty(unloaded)
+    for name in unloaded
+      call s:lod([name], ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
+    endfor
+    call s:dobufread(unloaded)
+    return 1
+  end
+  return 0
+endfunction
+
+function! s:remove_triggers(name)
+  if !has_key(s:triggers, a:name)
+    return
+  endif
+  for cmd in s:triggers[a:name].cmd
+    execute 'silent! delc' cmd
+  endfor
+  for map in s:triggers[a:name].map
+    execute 'silent! unmap' map
+    execute 'silent! iunmap' map
+  endfor
+  call remove(s:triggers, a:name)
+endfunction
+
+function! s:lod(names, types, ...)
+  for name in a:names
+    call s:remove_triggers(name)
+    let s:loaded[name] = 1
+  endfor
+  call s:reorg_rtp()
+
+  for name in a:names
+    let rtp = s:rtp(g:plugs[name])
+    for dir in a:types
+      call s:source(rtp, dir.'/**/*.vim')
+    endfor
+    if a:0
+      if !s:source(rtp, a:1) && !empty(s:glob(rtp, a:2))
+        execute 'runtime' a:1
+      endif
+      call s:source(rtp, a:2)
+    endif
+    call s:doautocmd('User', name)
+  endfor
+endfunction
+
+function! s:lod_ft(pat, names)
+  let syn = 'syntax/'.a:pat.'.vim'
+  call s:lod(a:names, ['plugin', 'after/plugin'], syn, 'after/'.syn)
+  execute 'autocmd! PlugLOD FileType' a:pat
+  call s:doautocmd('filetypeplugin', 'FileType')
+  call s:doautocmd('filetypeindent', 'FileType')
+endfunction
+
+function! s:lod_cmd(cmd, bang, l1, l2, args, names)
+  call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
+  call s:dobufread(a:names)
+  execute printf('%s%s%s %s', (a:l1 == a:l2 ? '' : (a:l1.','.a:l2)), a:cmd, a:bang, a:args)
+endfunction
+
+function! s:lod_map(map, names, with_prefix, prefix)
+  call s:lod(a:names, ['ftdetect', 'after/ftdetect', 'plugin', 'after/plugin'])
+  call s:dobufread(a:names)
+  let extra = ''
+  while 1
+    let c = getchar(0)
+    if c == 0
+      break
+    endif
+    let extra .= nr2char(c)
+  endwhile
+
+  if a:with_prefix
+    let prefix = v:count ? v:count : ''
+    let prefix .= '"'.v:register.a:prefix
+    if mode(1) == 'no'
+      if v:operator == 'c'
+        let prefix = "\<esc>" . prefix
+      endif
+      let prefix .= v:operator
+    endif
+    call feedkeys(prefix, 'n')
+  endif
+  call feedkeys(substitute(a:map, '^<Plug>', "\<Plug>", '') . extra)
+endfunction
+
+function! plug#(repo, ...)
+  if a:0 > 1
+    return s:err('Invalid number of arguments (1..2)')
+  endif
+
+  try
+    let repo = s:trim(a:repo)
+    let opts = a:0 == 1 ? s:parse_options(a:1) : s:base_spec
+    let name = get(opts, 'as', s:plug_fnamemodify(repo, ':t:s?\.git$??'))
+    let spec = extend(s:infer_properties(name, repo), opts)
+    if !has_key(g:plugs, name)
+      call add(g:plugs_order, name)
+    endif
+    let g:plugs[name] = spec
+    let s:loaded[name] = get(s:loaded, name, 0)
+  catch
+    return s:err(repo . ' ' . v:exception)
+  endtry
+endfunction
+
+function! s:parse_options(arg)
+  let opts = copy(s:base_spec)
+  let type = type(a:arg)
+  let opt_errfmt = 'Invalid argument for "%s" option of :Plug (expected: %s)'
+  if type == s:TYPE.string
+    if empty(a:arg)
+      throw printf(opt_errfmt, 'tag', 'string')
+    endif
+    let opts.tag = a:arg
+  elseif type == s:TYPE.dict
+    for opt in ['branch', 'tag', 'commit', 'rtp', 'dir', 'as']
+      if has_key(a:arg, opt)
+      \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))
+        throw printf(opt_errfmt, opt, 'string')
+      endif
+    endfor
+    for opt in ['on', 'for']
+      if has_key(a:arg, opt)
+      \ && type(a:arg[opt]) != s:TYPE.list
+      \ && (type(a:arg[opt]) != s:TYPE.string || empty(a:arg[opt]))
+        throw printf(opt_errfmt, opt, 'string or list')
+      endif
+    endfor
+    if has_key(a:arg, 'do')
+      \ && type(a:arg.do) != s:TYPE.funcref
+      \ && (type(a:arg.do) != s:TYPE.string || empty(a:arg.do))
+        throw printf(opt_errfmt, 'do', 'string or funcref')
+    endif
+    call extend(opts, a:arg)
+    if has_key(opts, 'dir')
+      let opts.dir = s:dirpath(s:plug_expand(opts.dir))
+    endif
+  else
+    throw 'Invalid argument type (expected: string or dictionary)'
+  endif
+  return opts
+endfunction
+
+function! s:infer_properties(name, repo)
+  let repo = a:repo
+  if s:is_local_plug(repo)
+    return { 'dir': s:dirpath(s:plug_expand(repo)) }
+  else
+    if repo =~ ':'
+      let uri = repo
+    else
+      if repo !~ '/'
+        throw printf('Invalid argument: %s (implicit `vim-scripts'' expansion is deprecated)', repo)
+      endif
+      let fmt = get(g:, 'plug_url_format', 'https://git::@github.com/%s.git')
+      let uri = printf(fmt, repo)
+    endif
+    return { 'dir': s:dirpath(g:plug_home.'/'.a:name), 'uri': uri }
+  endif
+endfunction
+
+function! s:install(force, names)
+  call s:update_impl(0, a:force, a:names)
+endfunction
+
+function! s:update(force, names)
+  call s:update_impl(1, a:force, a:names)
+endfunction
+
+function! plug#helptags()
+  if !exists('g:plugs')
+    return s:err('plug#begin was not called')
+  endif
+  for spec in values(g:plugs)
+    let docd = join([s:rtp(spec), 'doc'], '/')
+    if isdirectory(docd)
+      silent! execute 'helptags' s:esc(docd)
+    endif
+  endfor
+  return 1
+endfunction
+
+function! s:syntax()
+  syntax clear
+  syntax region plug1 start=/\%1l/ end=/\%2l/ contains=plugNumber
+  syntax region plug2 start=/\%2l/ end=/\%3l/ contains=plugBracket,plugX
+  syn match plugNumber /[0-9]\+[0-9.]*/ contained
+  syn match plugBracket /[[\]]/ contained
+  syn match plugX /x/ contained
+  syn match plugDash /^-\{1}\ /
+  syn match plugPlus /^+/
+  syn match plugStar /^*/
+  syn match plugMessage /\(^- \)\@<=.*/
+  syn match plugName /\(^- \)\@<=[^ ]*:/
+  syn match plugSha /\%(: \)\@<=[0-9a-f]\{4,}$/
+  syn match plugTag /(tag: [^)]\+)/
+  syn match plugInstall /\(^+ \)\@<=[^:]*/
+  syn match plugUpdate /\(^* \)\@<=[^:]*/
+  syn match plugCommit /^  \X*[0-9a-f]\{7,9} .*/ contains=plugRelDate,plugEdge,plugTag
+  syn match plugEdge /^  \X\+$/
+  syn match plugEdge /^  \X*/ contained nextgroup=plugSha
+  syn match plugSha /[0-9a-f]\{7,9}/ contained
+  syn match plugRelDate /([^)]*)$/ contained
+  syn match plugNotLoaded /(not loaded)$/
+  syn match plugError /^x.*/
+  syn region plugDeleted start=/^\~ .*/ end=/^\ze\S/
+  syn match plugH2 /^.*:\n-\+$/
+  syn match plugH2 /^-\{2,}/
+  syn keyword Function PlugInstall PlugStatus PlugUpdate PlugClean
+  hi def link plug1       Title
+  hi def link plug2       Repeat
+  hi def link plugH2      Type
+  hi def link plugX       Exception
+  hi def link plugBracket Structure
+  hi def link plugNumber  Number
+
+  hi def link plugDash    Special
+  hi def link plugPlus    Constant
+  hi def link plugStar    Boolean
+
+  hi def link plugMessage Function
+  hi def link plugName    Label
+  hi def link plugInstall Function
+  hi def link plugUpdate  Type
+
+  hi def link plugError   Error
+  hi def link plugDeleted Ignore
+  hi def link plugRelDate Comment
+  hi def link plugEdge    PreProc
+  hi def link plugSha     Identifier
+  hi def link plugTag     Constant
+
+  hi def link plugNotLoaded Comment
+endfunction
+
+function! s:lpad(str, len)
+  return a:str . repeat(' ', a:len - len(a:str))
+endfunction
+
+function! s:lines(msg)
+  return split(a:msg, "[\r\n]")
+endfunction
+
+function! s:lastline(msg)
+  return get(s:lines(a:msg), -1, '')
+endfunction
+
+function! s:new_window()
+  execute get(g:, 'plug_window', 'vertical topleft new')
+endfunction
+
+function! s:plug_window_exists()
+  let buflist = tabpagebuflist(s:plug_tab)
+  return !empty(buflist) && index(buflist, s:plug_buf) >= 0
+endfunction
+
+function! s:switch_in()
+  if !s:plug_window_exists()
+    return 0
+  endif
+
+  if winbufnr(0) != s:plug_buf
+    let s:pos = [tabpagenr(), winnr(), winsaveview()]
+    execute 'normal!' s:plug_tab.'gt'
+    let winnr = bufwinnr(s:plug_buf)
+    execute winnr.'wincmd w'
+    call add(s:pos, winsaveview())
+  else
+    let s:pos = [winsaveview()]
+  endif
+
+  setlocal modifiable
+  return 1
+endfunction
+
+function! s:switch_out(...)
+  call winrestview(s:pos[-1])
+  setlocal nomodifiable
+  if a:0 > 0
+    execute a:1
+  endif
+
+  if len(s:pos) > 1
+    execute 'normal!' s:pos[0].'gt'
+    execute s:pos[1] 'wincmd w'
+    call winrestview(s:pos[2])
+  endif
+endfunction
+
+function! s:finish_bindings()
+  nnoremap <silent> <buffer> R  :call <SID>retry()<cr>
+  nnoremap <silent> <buffer> D  :PlugDiff<cr>
+  nnoremap <silent> <buffer> S  :PlugStatus<cr>
+  nnoremap <silent> <buffer> U  :call <SID>status_update()<cr>
+  xnoremap <silent> <buffer> U  :call <SID>status_update()<cr>
+  nnoremap <silent> <buffer> ]] :silent! call <SID>section('')<cr>
+  nnoremap <silent> <buffer> [[ :silent! call <SID>section('b')<cr>
+endfunction
+
+function! s:prepare(...)
+  if empty(s:plug_getcwd())
+    throw 'Invalid current working directory. Cannot proceed.'
+  endif
+
+  for evar in ['$GIT_DIR', '$GIT_WORK_TREE']
+    if exists(evar)
+      throw evar.' detected. Cannot proceed.'
+    endif
+  endfor
+
+  call s:job_abort()
+  if s:switch_in()
+    if b:plug_preview == 1
+      pc
+    endif
+    enew
+  else
+    call s:new_window()
+  endif
+
+  nnoremap <silent> <buffer> q  :if b:plug_preview==1<bar>pc<bar>endif<bar>bd<cr>
+  if a:0 == 0
+    call s:finish_bindings()
+  endif
+  let b:plug_preview = -1
+  let s:plug_tab = tabpagenr()
+  let s:plug_buf = winbufnr(0)
+  call s:assign_name()
+
+  for k in ['<cr>', 'L', 'o', 'X', 'd', 'dd']
+    execute 'silent! unmap <buffer>' k
+  endfor
+  setlocal buftype=nofile bufhidden=wipe nobuflisted nolist noswapfile nowrap cursorline modifiable nospell
+  if exists('+colorcolumn')
+    setlocal colorcolumn=
+  endif
+  setf vim-plug
+  if exists('g:syntax_on')
+    call s:syntax()
+  endif
+endfunction
+
+function! s:assign_name()
+  " Assign buffer name
+  let prefix = '[Plugins]'
+  let name   = prefix
+  let idx    = 2
+  while bufexists(name)
+    let name = printf('%s (%s)', prefix, idx)
+    let idx = idx + 1
+  endwhile
+  silent! execute 'f' fnameescape(name)
+endfunction
+
+function! s:chsh(swap)
+  let prev = [&shell, &shellcmdflag, &shellredir]
+  if !s:is_win
+    set shell=sh
+  endif
+  if a:swap
+    if &shell =~# 'powershell\(\.exe\)\?$' || &shell =~# 'pwsh$'
+      let &shellredir = '2>&1 | Out-File -Encoding UTF8 %s'
+    elseif &shell =~# 'sh' || &shell =~# 'cmd\(\.exe\)\?$'
+      set shellredir=>%s\ 2>&1
+    endif
+  endif
+  return prev
+endfunction
+
+function! s:bang(cmd, ...)
+  let batchfile = ''
+  try
+    let [sh, shellcmdflag, shrd] = s:chsh(a:0)
+    " FIXME: Escaping is incomplete. We could use shellescape with eval,
+    "        but it won't work on Windows.
+    let cmd = a:0 ? s:with_cd(a:cmd, a:1) : a:cmd
+    if s:is_win
+      let [batchfile, cmd] = s:batchfile(cmd)
+    endif
+    let g:_plug_bang = (s:is_win && has('gui_running') ? 'silent ' : '').'!'.escape(cmd, '#!%')
+    execute "normal! :execute g:_plug_bang\<cr>\<cr>"
+  finally
+    unlet g:_plug_bang
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win && filereadable(batchfile)
+      call delete(batchfile)
+    endif
+  endtry
+  return v:shell_error ? 'Exit status: ' . v:shell_error : ''
+endfunction
+
+function! s:regress_bar()
+  let bar = substitute(getline(2)[1:-2], '.*\zs=', 'x', '')
+  call s:progress_bar(2, bar, len(bar))
+endfunction
+
+function! s:is_updated(dir)
+  return !empty(s:system_chomp(['git', 'log', '--pretty=format:%h', 'HEAD...HEAD@{1}'], a:dir))
+endfunction
+
+function! s:do(pull, force, todo)
+  for [name, spec] in items(a:todo)
+    if !isdirectory(spec.dir)
+      continue
+    endif
+    let installed = has_key(s:update.new, name)
+    let updated = installed ? 0 :
+      \ (a:pull && index(s:update.errors, name) < 0 && s:is_updated(spec.dir))
+    if a:force || installed || updated
+      execute 'cd' s:esc(spec.dir)
+      call append(3, '- Post-update hook for '. name .' ... ')
+      let error = ''
+      let type = type(spec.do)
+      if type == s:TYPE.string
+        if spec.do[0] == ':'
+          if !get(s:loaded, name, 0)
+            let s:loaded[name] = 1
+            call s:reorg_rtp()
+          endif
+          call s:load_plugin(spec)
+          try
+            execute spec.do[1:]
+          catch
+            let error = v:exception
+          endtry
+          if !s:plug_window_exists()
+            cd -
+            throw 'Warning: vim-plug was terminated by the post-update hook of '.name
+          endif
+        else
+          let error = s:bang(spec.do)
+        endif
+      elseif type == s:TYPE.funcref
+        try
+          call s:load_plugin(spec)
+          let status = installed ? 'installed' : (updated ? 'updated' : 'unchanged')
+          call spec.do({ 'name': name, 'status': status, 'force': a:force })
+        catch
+          let error = v:exception
+        endtry
+      else
+        let error = 'Invalid hook type'
+      endif
+      call s:switch_in()
+      call setline(4, empty(error) ? (getline(4) . 'OK')
+                                 \ : ('x' . getline(4)[1:] . error))
+      if !empty(error)
+        call add(s:update.errors, name)
+        call s:regress_bar()
+      endif
+      cd -
+    endif
+  endfor
+endfunction
+
+function! s:hash_match(a, b)
+  return stridx(a:a, a:b) == 0 || stridx(a:b, a:a) == 0
+endfunction
+
+function! s:checkout(spec)
+  let sha = a:spec.commit
+  let output = s:git_revision(a:spec.dir)
+  if !empty(output) && !s:hash_match(sha, s:lines(output)[0])
+    let credential_helper = s:git_version_requirement(2) ? '-c credential.helper= ' : ''
+    let output = s:system(
+          \ 'git '.credential_helper.'fetch --depth 999999 && git checkout '.plug#shellescape(sha).' --', a:spec.dir)
+  endif
+  return output
+endfunction
+
+function! s:finish(pull)
+  let new_frozen = len(filter(keys(s:update.new), 'g:plugs[v:val].frozen'))
+  if new_frozen
+    let s = new_frozen > 1 ? 's' : ''
+    call append(3, printf('- Installed %d frozen plugin%s', new_frozen, s))
+  endif
+  call append(3, '- Finishing ... ') | 4
+  redraw
+  call plug#helptags()
+  call plug#end()
+  call setline(4, getline(4) . 'Done!')
+  redraw
+  let msgs = []
+  if !empty(s:update.errors)
+    call add(msgs, "Press 'R' to retry.")
+  endif
+  if a:pull && len(s:update.new) < len(filter(getline(5, '$'),
+                \ "v:val =~ '^- ' && v:val !~# 'Already up.to.date'"))
+    call add(msgs, "Press 'D' to see the updated changes.")
+  endif
+  echo join(msgs, ' ')
+  call s:finish_bindings()
+endfunction
+
+function! s:retry()
+  if empty(s:update.errors)
+    return
+  endif
+  echo
+  call s:update_impl(s:update.pull, s:update.force,
+        \ extend(copy(s:update.errors), [s:update.threads]))
+endfunction
+
+function! s:is_managed(name)
+  return has_key(g:plugs[a:name], 'uri')
+endfunction
+
+function! s:names(...)
+  return sort(filter(keys(g:plugs), 'stridx(v:val, a:1) == 0 && s:is_managed(v:val)'))
+endfunction
+
+function! s:check_ruby()
+  silent! ruby require 'thread'; VIM::command("let g:plug_ruby = '#{RUBY_VERSION}'")
+  if !exists('g:plug_ruby')
+    redraw!
+    return s:warn('echom', 'Warning: Ruby interface is broken')
+  endif
+  let ruby_version = split(g:plug_ruby, '\.')
+  unlet g:plug_ruby
+  return s:version_requirement(ruby_version, [1, 8, 7])
+endfunction
+
+function! s:update_impl(pull, force, args) abort
+  let sync = index(a:args, '--sync') >= 0 || has('vim_starting')
+  let args = filter(copy(a:args), 'v:val != "--sync"')
+  let threads = (len(args) > 0 && args[-1] =~ '^[1-9][0-9]*$') ?
+                  \ remove(args, -1) : get(g:, 'plug_threads', 16)
+
+  let managed = filter(copy(g:plugs), 's:is_managed(v:key)')
+  let todo = empty(args) ? filter(managed, '!v:val.frozen || !isdirectory(v:val.dir)') :
+                         \ filter(managed, 'index(args, v:key) >= 0')
+
+  if empty(todo)
+    return s:warn('echo', 'No plugin to '. (a:pull ? 'update' : 'install'))
+  endif
+
+  if !s:is_win && s:git_version_requirement(2, 3)
+    let s:git_terminal_prompt = exists('$GIT_TERMINAL_PROMPT') ? $GIT_TERMINAL_PROMPT : ''
+    let $GIT_TERMINAL_PROMPT = 0
+    for plug in values(todo)
+      let plug.uri = substitute(plug.uri,
+            \ '^https://git::@github\.com', 'https://github.com', '')
+    endfor
+  endif
+
+  if !isdirectory(g:plug_home)
+    try
+      call mkdir(g:plug_home, 'p')
+    catch
+      return s:err(printf('Invalid plug directory: %s. '.
+              \ 'Try to call plug#begin with a valid directory', g:plug_home))
+    endtry
+  endif
+
+  if has('nvim') && !exists('*jobwait') && threads > 1
+    call s:warn('echom', '[vim-plug] Update Neovim for parallel installer')
+  endif
+
+  let use_job = s:nvim || s:vim8
+  let python = (has('python') || has('python3')) && !use_job
+  let ruby = has('ruby') && !use_job && (v:version >= 703 || v:version == 702 && has('patch374')) && !(s:is_win && has('gui_running')) && threads > 1 && s:check_ruby()
+
+  let s:update = {
+    \ 'start':   reltime(),
+    \ 'all':     todo,
+    \ 'todo':    copy(todo),
+    \ 'errors':  [],
+    \ 'pull':    a:pull,
+    \ 'force':   a:force,
+    \ 'new':     {},
+    \ 'threads': (python || ruby || use_job) ? min([len(todo), threads]) : 1,
+    \ 'bar':     '',
+    \ 'fin':     0
+  \ }
+
+  call s:prepare(1)
+  call append(0, ['', ''])
+  normal! 2G
+  silent! redraw
+
+  let s:clone_opt = []
+  if get(g:, 'plug_shallow', 1)
+    call extend(s:clone_opt, ['--depth', '1'])
+    if s:git_version_requirement(1, 7, 10)
+      call add(s:clone_opt, '--no-single-branch')
+    endif
+  endif
+
+  if has('win32unix') || has('wsl')
+    call extend(s:clone_opt, ['-c', 'core.eol=lf', '-c', 'core.autocrlf=input'])
+  endif
+
+  let s:submodule_opt = s:git_version_requirement(2, 8) ? ' --jobs='.threads : ''
+
+  " Python version requirement (>= 2.7)
+  if python && !has('python3') && !ruby && !use_job && s:update.threads > 1
+    redir => pyv
+    silent python import platform; print platform.python_version()
+    redir END
+    let python = s:version_requirement(
+          \ map(split(split(pyv)[0], '\.'), 'str2nr(v:val)'), [2, 6])
+  endif
+
+  if (python || ruby) && s:update.threads > 1
+    try
+      let imd = &imd
+      if s:mac_gui
+        set noimd
+      endif
+      if ruby
+        call s:update_ruby()
+      else
+        call s:update_python()
+      endif
+    catch
+      let lines = getline(4, '$')
+      let printed = {}
+      silent! 4,$d _
+      for line in lines
+        let name = s:extract_name(line, '.', '')
+        if empty(name) || !has_key(printed, name)
+          call append('$', line)
+          if !empty(name)
+            let printed[name] = 1
+            if line[0] == 'x' && index(s:update.errors, name) < 0
+              call add(s:update.errors, name)
+            end
+          endif
+        endif
+      endfor
+    finally
+      let &imd = imd
+      call s:update_finish()
+    endtry
+  else
+    call s:update_vim()
+    while use_job && sync
+      sleep 100m
+      if s:update.fin
+        break
+      endif
+    endwhile
+  endif
+endfunction
+
+function! s:log4(name, msg)
+  call setline(4, printf('- %s (%s)', a:msg, a:name))
+  redraw
+endfunction
+
+function! s:update_finish()
+  if exists('s:git_terminal_prompt')
+    let $GIT_TERMINAL_PROMPT = s:git_terminal_prompt
+  endif
+  if s:switch_in()
+    call append(3, '- Updating ...') | 4
+    for [name, spec] in items(filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && (s:update.force || s:update.pull || has_key(s:update.new, v:key))'))
+      let [pos, _] = s:logpos(name)
+      if !pos
+        continue
+      endif
+      if has_key(spec, 'commit')
+        call s:log4(name, 'Checking out '.spec.commit)
+        let out = s:checkout(spec)
+      elseif has_key(spec, 'tag')
+        let tag = spec.tag
+        if tag =~ '\*'
+          let tags = s:lines(s:system('git tag --list '.plug#shellescape(tag).' --sort -version:refname 2>&1', spec.dir))
+          if !v:shell_error && !empty(tags)
+            let tag = tags[0]
+            call s:log4(name, printf('Latest tag for %s -> %s', spec.tag, tag))
+            call append(3, '')
+          endif
+        endif
+        call s:log4(name, 'Checking out '.tag)
+        let out = s:system('git checkout -q '.plug#shellescape(tag).' -- 2>&1', spec.dir)
+      else
+        let branch = s:git_origin_branch(spec)
+        call s:log4(name, 'Merging origin/'.s:esc(branch))
+        let out = s:system('git checkout -q '.plug#shellescape(branch).' -- 2>&1'
+              \. (has_key(s:update.new, name) ? '' : ('&& git merge --ff-only '.plug#shellescape('origin/'.branch).' 2>&1')), spec.dir)
+      endif
+      if !v:shell_error && filereadable(spec.dir.'/.gitmodules') &&
+            \ (s:update.force || has_key(s:update.new, name) || s:is_updated(spec.dir))
+        call s:log4(name, 'Updating submodules. This may take a while.')
+        let out .= s:bang('git submodule update --init --recursive'.s:submodule_opt.' 2>&1', spec.dir)
+      endif
+      let msg = s:format_message(v:shell_error ? 'x': '-', name, out)
+      if v:shell_error
+        call add(s:update.errors, name)
+        call s:regress_bar()
+        silent execute pos 'd _'
+        call append(4, msg) | 4
+      elseif !empty(out)
+        call setline(pos, msg[0])
+      endif
+      redraw
+    endfor
+    silent 4 d _
+    try
+      call s:do(s:update.pull, s:update.force, filter(copy(s:update.all), 'index(s:update.errors, v:key) < 0 && has_key(v:val, "do")'))
+    catch
+      call s:warn('echom', v:exception)
+      call s:warn('echo', '')
+      return
+    endtry
+    call s:finish(s:update.pull)
+    call setline(1, 'Updated. Elapsed time: ' . split(reltimestr(reltime(s:update.start)))[0] . ' sec.')
+    call s:switch_out('normal! gg')
+  endif
+endfunction
+
+function! s:job_abort()
+  if (!s:nvim && !s:vim8) || !exists('s:jobs')
+    return
+  endif
+
+  for [name, j] in items(s:jobs)
+    if s:nvim
+      silent! call jobstop(j.jobid)
+    elseif s:vim8
+      silent! call job_stop(j.jobid)
+    endif
+    if j.new
+      call s:rm_rf(g:plugs[name].dir)
+    endif
+  endfor
+  let s:jobs = {}
+endfunction
+
+function! s:last_non_empty_line(lines)
+  let len = len(a:lines)
+  for idx in range(len)
+    let line = a:lines[len-idx-1]
+    if !empty(line)
+      return line
+    endif
+  endfor
+  return ''
+endfunction
+
+function! s:job_out_cb(self, data) abort
+  let self = a:self
+  let data = remove(self.lines, -1) . a:data
+  let lines = map(split(data, "\n", 1), 'split(v:val, "\r", 1)[-1]')
+  call extend(self.lines, lines)
+  " To reduce the number of buffer updates
+  let self.tick = get(self, 'tick', -1) + 1
+  if !self.running || self.tick % len(s:jobs) == 0
+    let bullet = self.running ? (self.new ? '+' : '*') : (self.error ? 'x' : '-')
+    let result = self.error ? join(self.lines, "\n") : s:last_non_empty_line(self.lines)
+    call s:log(bullet, self.name, result)
+  endif
+endfunction
+
+function! s:job_exit_cb(self, data) abort
+  let a:self.running = 0
+  let a:self.error = a:data != 0
+  call s:reap(a:self.name)
+  call s:tick()
+endfunction
+
+function! s:job_cb(fn, job, ch, data)
+  if !s:plug_window_exists() " plug window closed
+    return s:job_abort()
+  endif
+  call call(a:fn, [a:job, a:data])
+endfunction
+
+function! s:nvim_cb(job_id, data, event) dict abort
+  return (a:event == 'stdout' || a:event == 'stderr') ?
+    \ s:job_cb('s:job_out_cb',  self, 0, join(a:data, "\n")) :
+    \ s:job_cb('s:job_exit_cb', self, 0, a:data)
+endfunction
+
+function! s:spawn(name, cmd, opts)
+  let job = { 'name': a:name, 'running': 1, 'error': 0, 'lines': [''],
+            \ 'new': get(a:opts, 'new', 0) }
+  let s:jobs[a:name] = job
+
+  if s:nvim
+    if has_key(a:opts, 'dir')
+      let job.cwd = a:opts.dir
+    endif
+    let argv = a:cmd
+    call extend(job, {
+    \ 'on_stdout': function('s:nvim_cb'),
+    \ 'on_stderr': function('s:nvim_cb'),
+    \ 'on_exit':   function('s:nvim_cb'),
+    \ })
+    let jid = s:plug_call('jobstart', argv, job)
+    if jid > 0
+      let job.jobid = jid
+    else
+      let job.running = 0
+      let job.error   = 1
+      let job.lines   = [jid < 0 ? argv[0].' is not executable' :
+            \ 'Invalid arguments (or job table is full)']
+    endif
+  elseif s:vim8
+    let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"script": 0})'))
+    if has_key(a:opts, 'dir')
+      let cmd = s:with_cd(cmd, a:opts.dir, 0)
+    endif
+    let argv = s:is_win ? ['cmd', '/s', '/c', '"'.cmd.'"'] : ['sh', '-c', cmd]
+    let jid = job_start(s:is_win ? join(argv, ' ') : argv, {
+    \ 'out_cb':   function('s:job_cb', ['s:job_out_cb',  job]),
+    \ 'err_cb':   function('s:job_cb', ['s:job_out_cb',  job]),
+    \ 'exit_cb':  function('s:job_cb', ['s:job_exit_cb', job]),
+    \ 'err_mode': 'raw',
+    \ 'out_mode': 'raw'
+    \})
+    if job_status(jid) == 'run'
+      let job.jobid = jid
+    else
+      let job.running = 0
+      let job.error   = 1
+      let job.lines   = ['Failed to start job']
+    endif
+  else
+    let job.lines = s:lines(call('s:system', has_key(a:opts, 'dir') ? [a:cmd, a:opts.dir] : [a:cmd]))
+    let job.error = v:shell_error != 0
+    let job.running = 0
+  endif
+endfunction
+
+function! s:reap(name)
+  let job = s:jobs[a:name]
+  if job.error
+    call add(s:update.errors, a:name)
+  elseif get(job, 'new', 0)
+    let s:update.new[a:name] = 1
+  endif
+  let s:update.bar .= job.error ? 'x' : '='
+
+  let bullet = job.error ? 'x' : '-'
+  let result = job.error ? join(job.lines, "\n") : s:last_non_empty_line(job.lines)
+  call s:log(bullet, a:name, empty(result) ? 'OK' : result)
+  call s:bar()
+
+  call remove(s:jobs, a:name)
+endfunction
+
+function! s:bar()
+  if s:switch_in()
+    let total = len(s:update.all)
+    call setline(1, (s:update.pull ? 'Updating' : 'Installing').
+          \ ' plugins ('.len(s:update.bar).'/'.total.')')
+    call s:progress_bar(2, s:update.bar, total)
+    call s:switch_out()
+  endif
+endfunction
+
+function! s:logpos(name)
+  let max = line('$')
+  for i in range(4, max > 4 ? max : 4)
+    if getline(i) =~# '^[-+x*] '.a:name.':'
+      for j in range(i + 1, max > 5 ? max : 5)
+        if getline(j) !~ '^ '
+          return [i, j - 1]
+        endif
+      endfor
+      return [i, i]
+    endif
+  endfor
+  return [0, 0]
+endfunction
+
+function! s:log(bullet, name, lines)
+  if s:switch_in()
+    let [b, e] = s:logpos(a:name)
+    if b > 0
+      silent execute printf('%d,%d d _', b, e)
+      if b > winheight('.')
+        let b = 4
+      endif
+    else
+      let b = 4
+    endif
+    " FIXME For some reason, nomodifiable is set after :d in vim8
+    setlocal modifiable
+    call append(b - 1, s:format_message(a:bullet, a:name, a:lines))
+    call s:switch_out()
+  endif
+endfunction
+
+function! s:update_vim()
+  let s:jobs = {}
+
+  call s:bar()
+  call s:tick()
+endfunction
+
+function! s:tick()
+  let pull = s:update.pull
+  let prog = s:progress_opt(s:nvim || s:vim8)
+while 1 " Without TCO, Vim stack is bound to explode
+  if empty(s:update.todo)
+    if empty(s:jobs) && !s:update.fin
+      call s:update_finish()
+      let s:update.fin = 1
+    endif
+    return
+  endif
+
+  let name = keys(s:update.todo)[0]
+  let spec = remove(s:update.todo, name)
+  let new  = empty(globpath(spec.dir, '.git', 1))
+
+  call s:log(new ? '+' : '*', name, pull ? 'Updating ...' : 'Installing ...')
+  redraw
+
+  let has_tag = has_key(spec, 'tag')
+  if !new
+    let [error, _] = s:git_validate(spec, 0)
+    if empty(error)
+      if pull
+        let cmd = s:git_version_requirement(2) ? ['git', '-c', 'credential.helper=', 'fetch'] : ['git', 'fetch']
+        if has_tag && !empty(globpath(spec.dir, '.git/shallow'))
+          call extend(cmd, ['--depth', '99999999'])
+        endif
+        if !empty(prog)
+          call add(cmd, prog)
+        endif
+        call s:spawn(name, cmd, { 'dir': spec.dir })
+      else
+        let s:jobs[name] = { 'running': 0, 'lines': ['Already installed'], 'error': 0 }
+      endif
+    else
+      let s:jobs[name] = { 'running': 0, 'lines': s:lines(error), 'error': 1 }
+    endif
+  else
+    let cmd = ['git', 'clone']
+    if !has_tag
+      call extend(cmd, s:clone_opt)
+    endif
+    if !empty(prog)
+      call add(cmd, prog)
+    endif
+    call s:spawn(name, extend(cmd, [spec.uri, s:trim(spec.dir)]), { 'new': 1 })
+  endif
+
+  if !s:jobs[name].running
+    call s:reap(name)
+  endif
+  if len(s:jobs) >= s:update.threads
+    break
+  endif
+endwhile
+endfunction
+
+function! s:update_python()
+let py_exe = has('python') ? 'python' : 'python3'
+execute py_exe "<< EOF"
+import datetime
+import functools
+import os
+try:
+  import queue
+except ImportError:
+  import Queue as queue
+import random
+import re
+import shutil
+import signal
+import subprocess
+import tempfile
+import threading as thr
+import time
+import traceback
+import vim
+
+G_NVIM = vim.eval("has('nvim')") == '1'
+G_PULL = vim.eval('s:update.pull') == '1'
+G_RETRIES = int(vim.eval('get(g:, "plug_retries", 2)')) + 1
+G_TIMEOUT = int(vim.eval('get(g:, "plug_timeout", 60)'))
+G_CLONE_OPT = ' '.join(vim.eval('s:clone_opt'))
+G_PROGRESS = vim.eval('s:progress_opt(1)')
+G_LOG_PROB = 1.0 / int(vim.eval('s:update.threads'))
+G_STOP = thr.Event()
+G_IS_WIN = vim.eval('s:is_win') == '1'
+
+class PlugError(Exception):
+  def __init__(self, msg):
+    self.msg = msg
+class CmdTimedOut(PlugError):
+  pass
+class CmdFailed(PlugError):
+  pass
+class InvalidURI(PlugError):
+  pass
+class Action(object):
+  INSTALL, UPDATE, ERROR, DONE = ['+', '*', 'x', '-']
+
+class Buffer(object):
+  def __init__(self, lock, num_plugs, is_pull):
+    self.bar = ''
+    self.event = 'Updating' if is_pull else 'Installing'
+    self.lock = lock
+    self.maxy = int(vim.eval('winheight(".")'))
+    self.num_plugs = num_plugs
+
+  def __where(self, name):
+    """ Find first line with name in current buffer. Return line num. """
+    found, lnum = False, 0
+    matcher = re.compile('^[-+x*] {0}:'.format(name))
+    for line in vim.current.buffer:
+      if matcher.search(line) is not None:
+        found = True
+        break
+      lnum += 1
+
+    if not found:
+      lnum = -1
+    return lnum
+
+  def header(self):
+    curbuf = vim.current.buffer
+    curbuf[0] = self.event + ' plugins ({0}/{1})'.format(len(self.bar), self.num_plugs)
+
+    num_spaces = self.num_plugs - len(self.bar)
+    curbuf[1] = '[{0}{1}]'.format(self.bar, num_spaces * ' ')
+
+    with self.lock:
+      vim.command('normal! 2G')
+      vim.command('redraw')
+
+  def write(self, action, name, lines):
+    first, rest = lines[0], lines[1:]
+    msg = ['{0} {1}{2}{3}'.format(action, name, ': ' if first else '', first)]
+    msg.extend(['    ' + line for line in rest])
+
+    try:
+      if action == Action.ERROR:
+        self.bar += 'x'
+        vim.command("call add(s:update.errors, '{0}')".format(name))
+      elif action == Action.DONE:
+        self.bar += '='
+
+      curbuf = vim.current.buffer
+      lnum = self.__where(name)
+      if lnum != -1: # Found matching line num
+        del curbuf[lnum]
+        if lnum > self.maxy and action in set([Action.INSTALL, Action.UPDATE]):
+          lnum = 3
+      else:
+        lnum = 3
+      curbuf.append(msg, lnum)
+
+      self.header()
+    except vim.error:
+      pass
+
+class Command(object):
+  CD = 'cd /d' if G_IS_WIN else 'cd'
+
+  def __init__(self, cmd, cmd_dir=None, timeout=60, cb=None, clean=None):
+    self.cmd = cmd
+    if cmd_dir:
+      self.cmd = '{0} {1} && {2}'.format(Command.CD, cmd_dir, self.cmd)
+    self.timeout = timeout
+    self.callback = cb if cb else (lambda msg: None)
+    self.clean = clean if clean else (lambda: None)
+    self.proc = None
+
+  @property
+  def alive(self):
+    """ Returns true only if command still running. """
+    return self.proc and self.proc.poll() is None
+
+  def execute(self, ntries=3):
+    """ Execute the command with ntries if CmdTimedOut.
+        Returns the output of the command if no Exception.
+    """
+    attempt, finished, limit = 0, False, self.timeout
+
+    while not finished:
+      try:
+        attempt += 1
+        result = self.try_command()
+        finished = True
+        return result
+      except CmdTimedOut:
+        if attempt != ntries:
+          self.notify_retry()
+          self.timeout += limit
+        else:
+          raise
+
+  def notify_retry(self):
+    """ Retry required for command, notify user. """
+    for count in range(3, 0, -1):
+      if G_STOP.is_set():
+        raise KeyboardInterrupt
+      msg = 'Timeout. Will retry in {0} second{1} ...'.format(
+            count, 's' if count != 1 else '')
+      self.callback([msg])
+      time.sleep(1)
+    self.callback(['Retrying ...'])
+
+  def try_command(self):
+    """ Execute a cmd & poll for callback. Returns list of output.
+        Raises CmdFailed   -> return code for Popen isn't 0
+        Raises CmdTimedOut -> command exceeded timeout without new output
+    """
+    first_line = True
+
+    try:
+      tfile = tempfile.NamedTemporaryFile(mode='w+b')
+      preexec_fn = not G_IS_WIN and os.setsid or None
+      self.proc = subprocess.Popen(self.cmd, stdout=tfile,
+                                   stderr=subprocess.STDOUT,
+                                   stdin=subprocess.PIPE, shell=True,
+                                   preexec_fn=preexec_fn)
+      thrd = thr.Thread(target=(lambda proc: proc.wait()), args=(self.proc,))
+      thrd.start()
+
+      thread_not_started = True
+      while thread_not_started:
+        try:
+          thrd.join(0.1)
+          thread_not_started = False
+        except RuntimeError:
+          pass
+
+      while self.alive:
+        if G_STOP.is_set():
+          raise KeyboardInterrupt
+
+        if first_line or random.random() < G_LOG_PROB:
+          first_line = False
+          line = '' if G_IS_WIN else nonblock_read(tfile.name)
+          if line:
+            self.callback([line])
+
+        time_diff = time.time() - os.path.getmtime(tfile.name)
+        if time_diff > self.timeout:
+          raise CmdTimedOut(['Timeout!'])
+
+        thrd.join(0.5)
+
+      tfile.seek(0)
+      result = [line.decode('utf-8', 'replace').rstrip() for line in tfile]
+
+      if self.proc.returncode != 0:
+        raise CmdFailed([''] + result)
+
+      return result
+    except:
+      self.terminate()
+      raise
+
+  def terminate(self):
+    """ Terminate process and cleanup. """
+    if self.alive:
+      if G_IS_WIN:
+        os.kill(self.proc.pid, signal.SIGINT)
+      else:
+        os.killpg(self.proc.pid, signal.SIGTERM)
+    self.clean()
+
+class Plugin(object):
+  def __init__(self, name, args, buf_q, lock):
+    self.name = name
+    self.args = args
+    self.buf_q = buf_q
+    self.lock = lock
+    self.tag = args.get('tag', 0)
+
+  def manage(self):
+    try:
+      if os.path.exists(self.args['dir']):
+        self.update()
+      else:
+        self.install()
+        with self.lock:
+          thread_vim_command("let s:update.new['{0}'] = 1".format(self.name))
+    except PlugError as exc:
+      self.write(Action.ERROR, self.name, exc.msg)
+    except KeyboardInterrupt:
+      G_STOP.set()
+      self.write(Action.ERROR, self.name, ['Interrupted!'])
+    except:
+      # Any exception except those above print stack trace
+      msg = 'Trace:\n{0}'.format(traceback.format_exc().rstrip())
+      self.write(Action.ERROR, self.name, msg.split('\n'))
+      raise
+
+  def install(self):
+    target = self.args['dir']
+    if target[-1] == '\\':
+      target = target[0:-1]
+
+    def clean(target):
+      def _clean():
+        try:
+          shutil.rmtree(target)
+        except OSError:
+          pass
+      return _clean
+
+    self.write(Action.INSTALL, self.name, ['Installing ...'])
+    callback = functools.partial(self.write, Action.INSTALL, self.name)
+    cmd = 'git clone {0} {1} {2} {3} 2>&1'.format(
+          '' if self.tag else G_CLONE_OPT, G_PROGRESS, self.args['uri'],
+          esc(target))
+    com = Command(cmd, None, G_TIMEOUT, callback, clean(target))
+    result = com.execute(G_RETRIES)
+    self.write(Action.DONE, self.name, result[-1:])
+
+  def repo_uri(self):
+    cmd = 'git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url'
+    command = Command(cmd, self.args['dir'], G_TIMEOUT,)
+    result = command.execute(G_RETRIES)
+    return result[-1]
+
+  def update(self):
+    actual_uri = self.repo_uri()
+    expect_uri = self.args['uri']
+    regex = re.compile(r'^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$')
+    ma = regex.match(actual_uri)
+    mb = regex.match(expect_uri)
+    if ma is None or mb is None or ma.groups() != mb.groups():
+      msg = ['',
+             'Invalid URI: {0}'.format(actual_uri),
+             'Expected     {0}'.format(expect_uri),
+             'PlugClean required.']
+      raise InvalidURI(msg)
+
+    if G_PULL:
+      self.write(Action.UPDATE, self.name, ['Updating ...'])
+      callback = functools.partial(self.write, Action.UPDATE, self.name)
+      fetch_opt = '--depth 99999999' if self.tag and os.path.isfile(os.path.join(self.args['dir'], '.git/shallow')) else ''
+      cmd = 'git fetch {0} {1} 2>&1'.format(fetch_opt, G_PROGRESS)
+      com = Command(cmd, self.args['dir'], G_TIMEOUT, callback)
+      result = com.execute(G_RETRIES)
+      self.write(Action.DONE, self.name, result[-1:])
+    else:
+      self.write(Action.DONE, self.name, ['Already installed'])
+
+  def write(self, action, name, msg):
+    self.buf_q.put((action, name, msg))
+
+class PlugThread(thr.Thread):
+  def __init__(self, tname, args):
+    super(PlugThread, self).__init__()
+    self.tname = tname
+    self.args = args
+
+  def run(self):
+    thr.current_thread().name = self.tname
+    buf_q, work_q, lock = self.args
+
+    try:
+      while not G_STOP.is_set():
+        name, args = work_q.get_nowait()
+        plug = Plugin(name, args, buf_q, lock)
+        plug.manage()
+        work_q.task_done()
+    except queue.Empty:
+      pass
+
+class RefreshThread(thr.Thread):
+  def __init__(self, lock):
+    super(RefreshThread, self).__init__()
+    self.lock = lock
+    self.running = True
+
+  def run(self):
+    while self.running:
+      with self.lock:
+        thread_vim_command('noautocmd normal! a')
+      time.sleep(0.33)
+
+  def stop(self):
+    self.running = False
+
+if G_NVIM:
+  def thread_vim_command(cmd):
+    vim.session.threadsafe_call(lambda: vim.command(cmd))
+else:
+  def thread_vim_command(cmd):
+    vim.command(cmd)
+
+def esc(name):
+  return '"' + name.replace('"', '\"') + '"'
+
+def nonblock_read(fname):
+  """ Read a file with nonblock flag. Return the last line. """
+  fread = os.open(fname, os.O_RDONLY | os.O_NONBLOCK)
+  buf = os.read(fread, 100000).decode('utf-8', 'replace')
+  os.close(fread)
+
+  line = buf.rstrip('\r\n')
+  left = max(line.rfind('\r'), line.rfind('\n'))
+  if left != -1:
+    left += 1
+    line = line[left:]
+
+  return line
+
+def main():
+  thr.current_thread().name = 'main'
+  nthreads = int(vim.eval('s:update.threads'))
+  plugs = vim.eval('s:update.todo')
+  mac_gui = vim.eval('s:mac_gui') == '1'
+
+  lock = thr.Lock()
+  buf = Buffer(lock, len(plugs), G_PULL)
+  buf_q, work_q = queue.Queue(), queue.Queue()
+  for work in plugs.items():
+    work_q.put(work)
+
+  start_cnt = thr.active_count()
+  for num in range(nthreads):
+    tname = 'PlugT-{0:02}'.format(num)
+    thread = PlugThread(tname, (buf_q, work_q, lock))
+    thread.start()
+  if mac_gui:
+    rthread = RefreshThread(lock)
+    rthread.start()
+
+  while not buf_q.empty() or thr.active_count() != start_cnt:
+    try:
+      action, name, msg = buf_q.get(True, 0.25)
+      buf.write(action, name, ['OK'] if not msg else msg)
+      buf_q.task_done()
+    except queue.Empty:
+      pass
+    except KeyboardInterrupt:
+      G_STOP.set()
+
+  if mac_gui:
+    rthread.stop()
+    rthread.join()
+
+main()
+EOF
+endfunction
+
+function! s:update_ruby()
+  ruby << EOF
+  module PlugStream
+    SEP = ["\r", "\n", nil]
+    def get_line
+      buffer = ''
+      loop do
+        char = readchar rescue return
+        if SEP.include? char.chr
+          buffer << $/
+          break
+        else
+          buffer << char
+        end
+      end
+      buffer
+    end
+  end unless defined?(PlugStream)
+
+  def esc arg
+    %["#{arg.gsub('"', '\"')}"]
+  end
+
+  def killall pid
+    pids = [pid]
+    if /mswin|mingw|bccwin/ =~ RUBY_PLATFORM
+      pids.each { |pid| Process.kill 'INT', pid.to_i rescue nil }
+    else
+      unless `which pgrep 2> /dev/null`.empty?
+        children = pids
+        until children.empty?
+          children = children.map { |pid|
+            `pgrep -P #{pid}`.lines.map { |l| l.chomp }
+          }.flatten
+          pids += children
+        end
+      end
+      pids.each { |pid| Process.kill 'TERM', pid.to_i rescue nil }
+    end
+  end
+
+  def compare_git_uri a, b
+    regex = %r{^(?:\w+://)?(?:[^@/]*@)?([^:/]*(?::[0-9]*)?)[:/](.*?)(?:\.git)?/?$}
+    regex.match(a).to_a.drop(1) == regex.match(b).to_a.drop(1)
+  end
+
+  require 'thread'
+  require 'fileutils'
+  require 'timeout'
+  running = true
+  iswin = VIM::evaluate('s:is_win').to_i == 1
+  pull  = VIM::evaluate('s:update.pull').to_i == 1
+  base  = VIM::evaluate('g:plug_home')
+  all   = VIM::evaluate('s:update.todo')
+  limit = VIM::evaluate('get(g:, "plug_timeout", 60)')
+  tries = VIM::evaluate('get(g:, "plug_retries", 2)') + 1
+  nthr  = VIM::evaluate('s:update.threads').to_i
+  maxy  = VIM::evaluate('winheight(".")').to_i
+  vim7  = VIM::evaluate('v:version').to_i <= 703 && RUBY_PLATFORM =~ /darwin/
+  cd    = iswin ? 'cd /d' : 'cd'
+  tot   = VIM::evaluate('len(s:update.todo)') || 0
+  bar   = ''
+  skip  = 'Already installed'
+  mtx   = Mutex.new
+  take1 = proc { mtx.synchronize { running && all.shift } }
+  logh  = proc {
+    cnt = bar.length
+    $curbuf[1] = "#{pull ? 'Updating' : 'Installing'} plugins (#{cnt}/#{tot})"
+    $curbuf[2] = '[' + bar.ljust(tot) + ']'
+    VIM::command('normal! 2G')
+    VIM::command('redraw')
+  }
+  where = proc { |name| (1..($curbuf.length)).find { |l| $curbuf[l] =~ /^[-+x*] #{name}:/ } }
+  log   = proc { |name, result, type|
+    mtx.synchronize do
+      ing  = ![true, false].include?(type)
+      bar += type ? '=' : 'x' unless ing
+      b = case type
+          when :install  then '+' when :update then '*'
+          when true, nil then '-' else
+            VIM::command("call add(s:update.errors, '#{name}')")
+            'x'
+          end
+      result =
+        if type || type.nil?
+          ["#{b} #{name}: #{result.lines.to_a.last || 'OK'}"]
+        elsif result =~ /^Interrupted|^Timeout/
+          ["#{b} #{name}: #{result}"]
+        else
+          ["#{b} #{name}"] + result.lines.map { |l| "    " << l }
+        end
+      if lnum = where.call(name)
+        $curbuf.delete lnum
+        lnum = 4 if ing && lnum > maxy
+      end
+      result.each_with_index do |line, offset|
+        $curbuf.append((lnum || 4) - 1 + offset, line.gsub(/\e\[./, '').chomp)
+      end
+      logh.call
+    end
+  }
+  bt = proc { |cmd, name, type, cleanup|
+    tried = timeout = 0
+    begin
+      tried += 1
+      timeout += limit
+      fd = nil
+      data = ''
+      if iswin
+        Timeout::timeout(timeout) do
+          tmp = VIM::evaluate('tempname()')
+          system("(#{cmd}) > #{tmp}")
+          data = File.read(tmp).chomp
+          File.unlink tmp rescue nil
+        end
+      else
+        fd = IO.popen(cmd).extend(PlugStream)
+        first_line = true
+        log_prob = 1.0 / nthr
+        while line = Timeout::timeout(timeout) { fd.get_line }
+          data << line
+          log.call name, line.chomp, type if name && (first_line || rand < log_prob)
+          first_line = false
+        end
+        fd.close
+      end
+      [$? == 0, data.chomp]
+    rescue Timeout::Error, Interrupt => e
+      if fd && !fd.closed?
+        killall fd.pid
+        fd.close
+      end
+      cleanup.call if cleanup
+      if e.is_a?(Timeout::Error) && tried < tries
+        3.downto(1) do |countdown|
+          s = countdown > 1 ? 's' : ''
+          log.call name, "Timeout. Will retry in #{countdown} second#{s} ...", type
+          sleep 1
+        end
+        log.call name, 'Retrying ...', type
+        retry
+      end
+      [false, e.is_a?(Interrupt) ? "Interrupted!" : "Timeout!"]
+    end
+  }
+  main = Thread.current
+  threads = []
+  watcher = Thread.new {
+    if vim7
+      while VIM::evaluate('getchar(1)')
+        sleep 0.1
+      end
+    else
+      require 'io/console' # >= Ruby 1.9
+      nil until IO.console.getch == 3.chr
+    end
+    mtx.synchronize do
+      running = false
+      threads.each { |t| t.raise Interrupt } unless vim7
+    end
+    threads.each { |t| t.join rescue nil }
+    main.kill
+  }
+  refresh = Thread.new {
+    while true
+      mtx.synchronize do
+        break unless running
+        VIM::command('noautocmd normal! a')
+      end
+      sleep 0.2
+    end
+  } if VIM::evaluate('s:mac_gui') == 1
+
+  clone_opt = VIM::evaluate('s:clone_opt').join(' ')
+  progress = VIM::evaluate('s:progress_opt(1)')
+  nthr.times do
+    mtx.synchronize do
+      threads << Thread.new {
+        while pair = take1.call
+          name = pair.first
+          dir, uri, tag = pair.last.values_at *%w[dir uri tag]
+          exists = File.directory? dir
+          ok, result =
+            if exists
+              chdir = "#{cd} #{iswin ? dir : esc(dir)}"
+              ret, data = bt.call "#{chdir} && git rev-parse --abbrev-ref HEAD 2>&1 && git config -f .git/config remote.origin.url", nil, nil, nil
+              current_uri = data.lines.to_a.last
+              if !ret
+                if data =~ /^Interrupted|^Timeout/
+                  [false, data]
+                else
+                  [false, [data.chomp, "PlugClean required."].join($/)]
+                end
+              elsif !compare_git_uri(current_uri, uri)
+                [false, ["Invalid URI: #{current_uri}",
+                         "Expected:    #{uri}",
+                         "PlugClean required."].join($/)]
+              else
+                if pull
+                  log.call name, 'Updating ...', :update
+                  fetch_opt = (tag && File.exist?(File.join(dir, '.git/shallow'))) ? '--depth 99999999' : ''
+                  bt.call "#{chdir} && git fetch #{fetch_opt} #{progress} 2>&1", name, :update, nil
+                else
+                  [true, skip]
+                end
+              end
+            else
+              d = esc dir.sub(%r{[\\/]+$}, '')
+              log.call name, 'Installing ...', :install
+              bt.call "git clone #{clone_opt unless tag} #{progress} #{uri} #{d} 2>&1", name, :install, proc {
+                FileUtils.rm_rf dir
+              }
+            end
+          mtx.synchronize { VIM::command("let s:update.new['#{name}'] = 1") } if !exists && ok
+          log.call name, result, ok
+        end
+      } if running
+    end
+  end
+  threads.each { |t| t.join rescue nil }
+  logh.call
+  refresh.kill if refresh
+  watcher.kill
+EOF
+endfunction
+
+function! s:shellesc_cmd(arg, script)
+  let escaped = substitute('"'.a:arg.'"', '[&|<>()@^!"]', '^&', 'g')
+  return substitute(escaped, '%', (a:script ? '%' : '^') . '&', 'g')
+endfunction
+
+function! s:shellesc_ps1(arg)
+  return "'".substitute(escape(a:arg, '\"'), "'", "''", 'g')."'"
+endfunction
+
+function! s:shellesc_sh(arg)
+  return "'".substitute(a:arg, "'", "'\\\\''", 'g')."'"
+endfunction
+
+" Escape the shell argument based on the shell.
+" Vim and Neovim's shellescape() are insufficient.
+" 1. shellslash determines whether to use single/double quotes.
+"    Double-quote escaping is fragile for cmd.exe.
+" 2. It does not work for powershell.
+" 3. It does not work for *sh shells if the command is executed
+"    via cmd.exe (ie. cmd.exe /c sh -c command command_args)
+" 4. It does not support batchfile syntax.
+"
+" Accepts an optional dictionary with the following keys:
+" - shell: same as Vim/Neovim 'shell' option.
+"          If unset, fallback to 'cmd.exe' on Windows or 'sh'.
+" - script: If truthy and shell is cmd.exe, escape for batchfile syntax.
+function! plug#shellescape(arg, ...)
+  if a:arg =~# '^[A-Za-z0-9_/:.-]\+$'
+    return a:arg
+  endif
+  let opts = a:0 > 0 && type(a:1) == s:TYPE.dict ? a:1 : {}
+  let shell = get(opts, 'shell', s:is_win ? 'cmd.exe' : 'sh')
+  let script = get(opts, 'script', 1)
+  if shell =~# 'cmd\(\.exe\)\?$'
+    return s:shellesc_cmd(a:arg, script)
+  elseif shell =~# 'powershell\(\.exe\)\?$' || shell =~# 'pwsh$'
+    return s:shellesc_ps1(a:arg)
+  endif
+  return s:shellesc_sh(a:arg)
+endfunction
+
+function! s:glob_dir(path)
+  return map(filter(s:glob(a:path, '**'), 'isdirectory(v:val)'), 's:dirpath(v:val)')
+endfunction
+
+function! s:progress_bar(line, bar, total)
+  call setline(a:line, '[' . s:lpad(a:bar, a:total) . ']')
+endfunction
+
+function! s:compare_git_uri(a, b)
+  " See `git help clone'
+  " https:// [user@] github.com[:port] / junegunn/vim-plug [.git]
+  "          [git@]  github.com[:port] : junegunn/vim-plug [.git]
+  " file://                            / junegunn/vim-plug        [/]
+  "                                    / junegunn/vim-plug        [/]
+  let pat = '^\%(\w\+://\)\='.'\%([^@/]*@\)\='.'\([^:/]*\%(:[0-9]*\)\=\)'.'[:/]'.'\(.\{-}\)'.'\%(\.git\)\=/\?$'
+  let ma = matchlist(a:a, pat)
+  let mb = matchlist(a:b, pat)
+  return ma[1:2] ==# mb[1:2]
+endfunction
+
+function! s:format_message(bullet, name, message)
+  if a:bullet != 'x'
+    return [printf('%s %s: %s', a:bullet, a:name, s:lastline(a:message))]
+  else
+    let lines = map(s:lines(a:message), '"    ".v:val')
+    return extend([printf('x %s:', a:name)], lines)
+  endif
+endfunction
+
+function! s:with_cd(cmd, dir, ...)
+  let script = a:0 > 0 ? a:1 : 1
+  return printf('cd%s %s && %s', s:is_win ? ' /d' : '', plug#shellescape(a:dir, {'script': script}), a:cmd)
+endfunction
+
+function! s:system(cmd, ...)
+  let batchfile = ''
+  try
+    let [sh, shellcmdflag, shrd] = s:chsh(1)
+    if type(a:cmd) == s:TYPE.list
+      " Neovim's system() supports list argument to bypass the shell
+      " but it cannot set the working directory for the command.
+      " Assume that the command does not rely on the shell.
+      if has('nvim') && a:0 == 0
+        return system(a:cmd)
+      endif
+      let cmd = join(map(copy(a:cmd), 'plug#shellescape(v:val, {"shell": &shell, "script": 0})'))
+      if &shell =~# 'powershell\(\.exe\)\?$'
+        let cmd = '& ' . cmd
+      endif
+    else
+      let cmd = a:cmd
+    endif
+    if a:0 > 0
+      let cmd = s:with_cd(cmd, a:1, type(a:cmd) != s:TYPE.list)
+    endif
+    if s:is_win && type(a:cmd) != s:TYPE.list
+      let [batchfile, cmd] = s:batchfile(cmd)
+    endif
+    return system(cmd)
+  finally
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win && filereadable(batchfile)
+      call delete(batchfile)
+    endif
+  endtry
+endfunction
+
+function! s:system_chomp(...)
+  let ret = call('s:system', a:000)
+  return v:shell_error ? '' : substitute(ret, '\n$', '', '')
+endfunction
+
+function! s:git_validate(spec, check_branch)
+  let err = ''
+  if isdirectory(a:spec.dir)
+    let result = [s:git_local_branch(a:spec.dir), s:git_origin_url(a:spec.dir)]
+    let remote = result[-1]
+    if empty(remote)
+      let err = join([remote, 'PlugClean required.'], "\n")
+    elseif !s:compare_git_uri(remote, a:spec.uri)
+      let err = join(['Invalid URI: '.remote,
+                    \ 'Expected:    '.a:spec.uri,
+                    \ 'PlugClean required.'], "\n")
+    elseif a:check_branch && has_key(a:spec, 'commit')
+      let sha = s:git_revision(a:spec.dir)
+      if empty(sha)
+        let err = join(add(result, 'PlugClean required.'), "\n")
+      elseif !s:hash_match(sha, a:spec.commit)
+        let err = join([printf('Invalid HEAD (expected: %s, actual: %s)',
+                              \ a:spec.commit[:6], sha[:6]),
+                      \ 'PlugUpdate required.'], "\n")
+      endif
+    elseif a:check_branch
+      let current_branch = result[0]
+      " Check tag
+      let origin_branch = s:git_origin_branch(a:spec)
+      if has_key(a:spec, 'tag')
+        let tag = s:system_chomp('git describe --exact-match --tags HEAD 2>&1', a:spec.dir)
+        if a:spec.tag !=# tag && a:spec.tag !~ '\*'
+          let err = printf('Invalid tag: %s (expected: %s). Try PlugUpdate.',
+                \ (empty(tag) ? 'N/A' : tag), a:spec.tag)
+        endif
+      " Check branch
+      elseif origin_branch !=# current_branch
+        let err = printf('Invalid branch: %s (expected: %s). Try PlugUpdate.',
+              \ current_branch, origin_branch)
+      endif
+      if empty(err)
+        let [ahead, behind] = split(s:lastline(s:system([
+        \ 'git', 'rev-list', '--count', '--left-right',
+        \ printf('HEAD...origin/%s', origin_branch)
+        \ ], a:spec.dir)), '\t')
+        if !v:shell_error && ahead
+          if behind
+            " Only mention PlugClean if diverged, otherwise it's likely to be
+            " pushable (and probably not that messed up).
+            let err = printf(
+                  \ "Diverged from origin/%s (%d commit(s) ahead and %d commit(s) behind!\n"
+                  \ .'Backup local changes and run PlugClean and PlugUpdate to reinstall it.', origin_branch, ahead, behind)
+          else
+            let err = printf("Ahead of origin/%s by %d commit(s).\n"
+                  \ .'Cannot update until local changes are pushed.',
+                  \ origin_branch, ahead)
+          endif
+        endif
+      endif
+    endif
+  else
+    let err = 'Not found'
+  endif
+  return [err, err =~# 'PlugClean']
+endfunction
+
+function! s:rm_rf(dir)
+  if isdirectory(a:dir)
+    return s:system(s:is_win
+    \ ? 'rmdir /S /Q '.plug#shellescape(a:dir)
+    \ : ['rm', '-rf', a:dir])
+  endif
+endfunction
+
+function! s:clean(force)
+  call s:prepare()
+  call append(0, 'Searching for invalid plugins in '.g:plug_home)
+  call append(1, '')
+
+  " List of valid directories
+  let dirs = []
+  let errs = {}
+  let [cnt, total] = [0, len(g:plugs)]
+  for [name, spec] in items(g:plugs)
+    if !s:is_managed(name)
+      call add(dirs, spec.dir)
+    else
+      let [err, clean] = s:git_validate(spec, 1)
+      if clean
+        let errs[spec.dir] = s:lines(err)[0]
+      else
+        call add(dirs, spec.dir)
+      endif
+    endif
+    let cnt += 1
+    call s:progress_bar(2, repeat('=', cnt), total)
+    normal! 2G
+    redraw
+  endfor
+
+  let allowed = {}
+  for dir in dirs
+    let allowed[s:dirpath(s:plug_fnamemodify(dir, ':h:h'))] = 1
+    let allowed[dir] = 1
+    for child in s:glob_dir(dir)
+      let allowed[child] = 1
+    endfor
+  endfor
+
+  let todo = []
+  let found = sort(s:glob_dir(g:plug_home))
+  while !empty(found)
+    let f = remove(found, 0)
+    if !has_key(allowed, f) && isdirectory(f)
+      call add(todo, f)
+      call append(line('$'), '- ' . f)
+      if has_key(errs, f)
+        call append(line('$'), '    ' . errs[f])
+      endif
+      let found = filter(found, 'stridx(v:val, f) != 0')
+    end
+  endwhile
+
+  4
+  redraw
+  if empty(todo)
+    call append(line('$'), 'Already clean.')
+  else
+    let s:clean_count = 0
+    call append(3, ['Directories to delete:', ''])
+    redraw!
+    if a:force || s:ask_no_interrupt('Delete all directories?')
+      call s:delete([6, line('$')], 1)
+    else
+      call setline(4, 'Cancelled.')
+      nnoremap <silent> <buffer> d :set opfunc=<sid>delete_op<cr>g@
+      nmap     <silent> <buffer> dd d_
+      xnoremap <silent> <buffer> d :<c-u>call <sid>delete_op(visualmode(), 1)<cr>
+      echo 'Delete the lines (d{motion}) to delete the corresponding directories'
+    endif
+  endif
+  4
+  setlocal nomodifiable
+endfunction
+
+function! s:delete_op(type, ...)
+  call s:delete(a:0 ? [line("'<"), line("'>")] : [line("'["), line("']")], 0)
+endfunction
+
+function! s:delete(range, force)
+  let [l1, l2] = a:range
+  let force = a:force
+  let err_count = 0
+  while l1 <= l2
+    let line = getline(l1)
+    if line =~ '^- ' && isdirectory(line[2:])
+      execute l1
+      redraw!
+      let answer = force ? 1 : s:ask('Delete '.line[2:].'?', 1)
+      let force = force || answer > 1
+      if answer
+        let err = s:rm_rf(line[2:])
+        setlocal modifiable
+        if empty(err)
+          call setline(l1, '~'.line[1:])
+          let s:clean_count += 1
+        else
+          delete _
+          call append(l1 - 1, s:format_message('x', line[1:], err))
+          let l2 += len(s:lines(err))
+          let err_count += 1
+        endif
+        let msg = printf('Removed %d directories.', s:clean_count)
+        if err_count > 0
+          let msg .= printf(' Failed to remove %d directories.', err_count)
+        endif
+        call setline(4, msg)
+        setlocal nomodifiable
+      endif
+    endif
+    let l1 += 1
+  endwhile
+endfunction
+
+function! s:upgrade()
+  echo 'Downloading the latest version of vim-plug'
+  redraw
+  let tmp = s:plug_tempname()
+  let new = tmp . '/plug.vim'
+
+  try
+    let out = s:system(['git', 'clone', '--depth', '1', s:plug_src, tmp])
+    if v:shell_error
+      return s:err('Error upgrading vim-plug: '. out)
+    endif
+
+    if readfile(s:me) ==# readfile(new)
+      echo 'vim-plug is already up-to-date'
+      return 0
+    else
+      call rename(s:me, s:me . '.old')
+      call rename(new, s:me)
+      unlet g:loaded_plug
+      echo 'vim-plug has been upgraded'
+      return 1
+    endif
+  finally
+    silent! call s:rm_rf(tmp)
+  endtry
+endfunction
+
+function! s:upgrade_specs()
+  for spec in values(g:plugs)
+    let spec.frozen = get(spec, 'frozen', 0)
+  endfor
+endfunction
+
+function! s:status()
+  call s:prepare()
+  call append(0, 'Checking plugins')
+  call append(1, '')
+
+  let ecnt = 0
+  let unloaded = 0
+  let [cnt, total] = [0, len(g:plugs)]
+  for [name, spec] in items(g:plugs)
+    let is_dir = isdirectory(spec.dir)
+    if has_key(spec, 'uri')
+      if is_dir
+        let [err, _] = s:git_validate(spec, 1)
+        let [valid, msg] = [empty(err), empty(err) ? 'OK' : err]
+      else
+        let [valid, msg] = [0, 'Not found. Try PlugInstall.']
+      endif
+    else
+      if is_dir
+        let [valid, msg] = [1, 'OK']
+      else
+        let [valid, msg] = [0, 'Not found.']
+      endif
+    endif
+    let cnt += 1
+    let ecnt += !valid
+    " `s:loaded` entry can be missing if PlugUpgraded
+    if is_dir && get(s:loaded, name, -1) == 0
+      let unloaded = 1
+      let msg .= ' (not loaded)'
+    endif
+    call s:progress_bar(2, repeat('=', cnt), total)
+    call append(3, s:format_message(valid ? '-' : 'x', name, msg))
+    normal! 2G
+    redraw
+  endfor
+  call setline(1, 'Finished. '.ecnt.' error(s).')
+  normal! gg
+  setlocal nomodifiable
+  if unloaded
+    echo "Press 'L' on each line to load plugin, or 'U' to update"
+    nnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
+    xnoremap <silent> <buffer> L :call <SID>status_load(line('.'))<cr>
+  end
+endfunction
+
+function! s:extract_name(str, prefix, suffix)
+  return matchstr(a:str, '^'.a:prefix.' \zs[^:]\+\ze:.*'.a:suffix.'$')
+endfunction
+
+function! s:status_load(lnum)
+  let line = getline(a:lnum)
+  let name = s:extract_name(line, '-', '(not loaded)')
+  if !empty(name)
+    call plug#load(name)
+    setlocal modifiable
+    call setline(a:lnum, substitute(line, ' (not loaded)$', '', ''))
+    setlocal nomodifiable
+  endif
+endfunction
+
+function! s:status_update() range
+  let lines = getline(a:firstline, a:lastline)
+  let names = filter(map(lines, 's:extract_name(v:val, "[x-]", "")'), '!empty(v:val)')
+  if !empty(names)
+    echo
+    execute 'PlugUpdate' join(names)
+  endif
+endfunction
+
+function! s:is_preview_window_open()
+  silent! wincmd P
+  if &previewwindow
+    wincmd p
+    return 1
+  endif
+endfunction
+
+function! s:find_name(lnum)
+  for lnum in reverse(range(1, a:lnum))
+    let line = getline(lnum)
+    if empty(line)
+      return ''
+    endif
+    let name = s:extract_name(line, '-', '')
+    if !empty(name)
+      return name
+    endif
+  endfor
+  return ''
+endfunction
+
+function! s:preview_commit()
+  if b:plug_preview < 0
+    let b:plug_preview = !s:is_preview_window_open()
+  endif
+
+  let sha = matchstr(getline('.'), '^  \X*\zs[0-9a-f]\{7,9}')
+  if empty(sha)
+    return
+  endif
+
+  let name = s:find_name(line('.'))
+  if empty(name) || !has_key(g:plugs, name) || !isdirectory(g:plugs[name].dir)
+    return
+  endif
+
+  if exists('g:plug_pwindow') && !s:is_preview_window_open()
+    execute g:plug_pwindow
+    execute 'e' sha
+  else
+    execute 'pedit' sha
+    wincmd P
+  endif
+  setlocal previewwindow filetype=git buftype=nofile nobuflisted modifiable
+  let batchfile = ''
+  try
+    let [sh, shellcmdflag, shrd] = s:chsh(1)
+    let cmd = 'cd '.plug#shellescape(g:plugs[name].dir).' && git show --no-color --pretty=medium '.sha
+    if s:is_win
+      let [batchfile, cmd] = s:batchfile(cmd)
+    endif
+    execute 'silent %!' cmd
+  finally
+    let [&shell, &shellcmdflag, &shellredir] = [sh, shellcmdflag, shrd]
+    if s:is_win && filereadable(batchfile)
+      call delete(batchfile)
+    endif
+  endtry
+  setlocal nomodifiable
+  nnoremap <silent> <buffer> q :q<cr>
+  wincmd p
+endfunction
+
+function! s:section(flags)
+  call search('\(^[x-] \)\@<=[^:]\+:', a:flags)
+endfunction
+
+function! s:format_git_log(line)
+  let indent = '  '
+  let tokens = split(a:line, nr2char(1))
+  if len(tokens) != 5
+    return indent.substitute(a:line, '\s*$', '', '')
+  endif
+  let [graph, sha, refs, subject, date] = tokens
+  let tag = matchstr(refs, 'tag: [^,)]\+')
+  let tag = empty(tag) ? ' ' : ' ('.tag.') '
+  return printf('%s%s%s%s%s (%s)', indent, graph, sha, tag, subject, date)
+endfunction
+
+function! s:append_ul(lnum, text)
+  call append(a:lnum, ['', a:text, repeat('-', len(a:text))])
+endfunction
+
+function! s:diff()
+  call s:prepare()
+  call append(0, ['Collecting changes ...', ''])
+  let cnts = [0, 0]
+  let bar = ''
+  let total = filter(copy(g:plugs), 's:is_managed(v:key) && isdirectory(v:val.dir)')
+  call s:progress_bar(2, bar, len(total))
+  for origin in [1, 0]
+    let plugs = reverse(sort(items(filter(copy(total), (origin ? '' : '!').'(has_key(v:val, "commit") || has_key(v:val, "tag"))'))))
+    if empty(plugs)
+      continue
+    endif
+    call s:append_ul(2, origin ? 'Pending updates:' : 'Last update:')
+    for [k, v] in plugs
+      let branch = s:git_origin_branch(v)
+      if len(branch)
+        let range = origin ? '..origin/'.branch : 'HEAD@{1}..'
+        let cmd = ['git', 'log', '--graph', '--color=never']
+        if s:git_version_requirement(2, 10, 0)
+          call add(cmd, '--no-show-signature')
+        endif
+        call extend(cmd, ['--pretty=format:%x01%h%x01%d%x01%s%x01%cr', range])
+        if has_key(v, 'rtp')
+          call extend(cmd, ['--', v.rtp])
+        endif
+        let diff = s:system_chomp(cmd, v.dir)
+        if !empty(diff)
+          let ref = has_key(v, 'tag') ? (' (tag: '.v.tag.')') : has_key(v, 'commit') ? (' '.v.commit) : ''
+          call append(5, extend(['', '- '.k.':'.ref], map(s:lines(diff), 's:format_git_log(v:val)')))
+          let cnts[origin] += 1
+        endif
+      endif
+      let bar .= '='
+      call s:progress_bar(2, bar, len(total))
+      normal! 2G
+      redraw
+    endfor
+    if !cnts[origin]
+      call append(5, ['', 'N/A'])
+    endif
+  endfor
+  call setline(1, printf('%d plugin(s) updated.', cnts[0])
+        \ . (cnts[1] ? printf(' %d plugin(s) have pending updates.', cnts[1]) : ''))
+
+  if cnts[0] || cnts[1]
+    nnoremap <silent> <buffer> <plug>(plug-preview) :silent! call <SID>preview_commit()<cr>
+    if empty(maparg("\<cr>", 'n'))
+      nmap <buffer> <cr> <plug>(plug-preview)
+    endif
+    if empty(maparg('o', 'n'))
+      nmap <buffer> o <plug>(plug-preview)
+    endif
+  endif
+  if cnts[0]
+    nnoremap <silent> <buffer> X :call <SID>revert()<cr>
+    echo "Press 'X' on each block to revert the update"
+  endif
+  normal! gg
+  setlocal nomodifiable
+endfunction
+
+function! s:revert()
+  if search('^Pending updates', 'bnW')
+    return
+  endif
+
+  let name = s:find_name(line('.'))
+  if empty(name) || !has_key(g:plugs, name) ||
+    \ input(printf('Revert the update of %s? (y/N) ', name)) !~? '^y'
+    return
+  endif
+
+  call s:system('git reset --hard HEAD@{1} && git checkout '.plug#shellescape(g:plugs[name].branch).' --', g:plugs[name].dir)
+  setlocal modifiable
+  normal! "_dap
+  setlocal nomodifiable
+  echo 'Reverted'
+endfunction
+
+function! s:snapshot(force, ...) abort
+  call s:prepare()
+  setf vim
+  call append(0, ['" Generated by vim-plug',
+                \ '" '.strftime("%c"),
+                \ '" :source this file in vim to restore the snapshot',
+                \ '" or execute: vim -S snapshot.vim',
+                \ '', '', 'PlugUpdate!'])
+  1
+  let anchor = line('$') - 3
+  let names = sort(keys(filter(copy(g:plugs),
+        \'has_key(v:val, "uri") && !has_key(v:val, "commit") && isdirectory(v:val.dir)')))
+  for name in reverse(names)
+    let sha = s:git_revision(g:plugs[name].dir)
+    if !empty(sha)
+      call append(anchor, printf("silent! let g:plugs['%s'].commit = '%s'", name, sha))
+      redraw
+    endif
+  endfor
+
+  if a:0 > 0
+    let fn = s:plug_expand(a:1)
+    if filereadable(fn) && !(a:force || s:ask(a:1.' already exists. Overwrite?'))
+      return
+    endif
+    call writefile(getline(1, '$'), fn)
+    echo 'Saved as '.a:1
+    silent execute 'e' s:esc(fn)
+    setf vim
+  endif
+endfunction
+
+function! s:split_rtp()
+  return split(&rtp, '\\\@<!,')
+endfunction
+
+let s:first_rtp = s:escrtp(get(s:split_rtp(), 0, ''))
+let s:last_rtp  = s:escrtp(get(s:split_rtp(), -1, ''))
+
+if exists('g:plugs')
+  let g:plugs_order = get(g:, 'plugs_order', keys(g:plugs))
+  call s:upgrade_specs()
+  call s:define_commands()
+endif
+
+let &cpo = s:cpo_save
+unlet s:cpo_save

+ 257 - 0
dot-config/vim/vimrc

@@ -0,0 +1,257 @@
+"
+" noah's ~/.config/vim/vimrc
+" 
+" basic setup
+set nocompatible
+
+" set vim paths
+set undodir="~/.config/vim/undo"
+set viminfo="~/.config/vim/viminfo"
+set runtimepath+="~/.config/vim"
+
+" make :find recursive
+set path+=**
+
+" display all files for tab completion
+set wildmenu
+
+" making me comfortable
+set nu
+set tabstop=4 softtabstop=4
+set shiftwidth=4
+set expandtab
+set smartindent
+set smartcase
+set noswapfile
+set nobackup
+set incsearch
+set spelllang=de_ch,en
+
+" getting plugins
+call plug#begin('~/.cache/vim/plugged')
+
+" colorshemes
+Plug 'morhetz/gruvbox'
+"Plug 'itchyny/landscape.vim'
+
+
+" nice statusline for vim
+Plug 'vim-airline/vim-airline'
+
+" some git integration
+Plug 'tpope/vim-fugitive'
+
+" preview colours
+Plug 'ap/vim-css-color'
+
+" autocompletion plugins
+Plug 'neoclide/coc.nvim', {'branch': 'release'}
+"Plug 'lervag/vimtex'
+
+call plug#end()
+
+colorscheme gruvbox
+set background=dark
+
+let loaded_matchparen = 1
+let mapleader = " "
+
+let g:netrw_browse_split = 2
+let g:vrfr_rg = 'true'
+let g:netrw_banner = 0
+let g:netrw_winsize = 25
+
+vnoremap J :m '>+1<CR>gv=gv
+vnoremap K :m '<-2<CR>gv=gv
+
+nnoremap <leader>h :wincmd h<CR>
+nnoremap <leader>j wincmd j<CR>
+nnoremap <leader>k wincmd k<CR>
+nnoremap <leader>l wincmd l<CR>
+nnoremap <leader>u :UndotreeShow<CR>
+nnoremap <leader>pv :wincmd v<bar> :Ex <bar> :vertical resize 30<CR>
+nnoremap <leader>ps :Rg<CR>
+nnoremap <silent> <leader>+ :vertical resize +5<CR>
+nnoremap <silent> <leader>- :vertical resize -5<CR>
+
+" general custom commands
+command D filetype detect
+
+
+""" active to autocompile docs on saving
+"autocmd BufWritePost *.ms !compile % | fold -w200
+"autocmd BufWritePost *.tex !compile % | fold -w200
+
+"" commands for opening and compiling various document types
+command S silent !vshow '%:p'
+command C !compile "%"
+
+" general compile button
+map <F3> :w<CR>:!compile "%"; pkill -HUP mupdf<CR>
+
+" bibtex extra compiler
+map <F2> :w<CR>:!latexmk -pdf "%"; pkill -HUP mupdf<CR>
+
+map <F4> :noh<CR>
+map <F5> :set spell!<CR>
+map <F6> :w<CR>:!glosscompile "%"; pkill -HUP mupdf<CR>
+
+" set encoding
+set encoding=utf-8
+
+" automatic python syntax highlighting for .tibasic files
+autocmd BufNewFile,BufRead *.tibasic set filetype=python
+autocmd BufNewFile,BufRead *.tib set filetype=python
+
+" jumper
+vnoremap <Space><Space> <Esc>/<++><Enter>"_c4l
+map <Space><Space> <Esc>/<++><Enter>"_c4l
+
+""" START latex macros
+" standard macros
+autocmd FileType tex inoremap ;beg <Esc>yypkI\begin{<Esc>A}<Esc>o<Esc>0i<Esc>jI\end{<Esc>A}<CR><Esc>0i<CR><Esc>0i<++><Esc>3ki
+autocmd FileType tex inoremap ;ig \includegraphics[]{<++>}<Esc>6hi
+autocmd FileType tex inoremap ;tw width=\textwidth<Esc>9hi
+autocmd FileType tex inoremap ;th height=\textheight<Esc>10hi
+autocmd FileType tex inoremap ;ni \setlength{\parindent}{0em}<Esc>
+
+" packages
+autocmd FileType tex inoremap ;ger \usepackage[ngerman]{babel}<Esc>
+
+" text formatting macros
+autocmd FileType tex inoremap ;bf \textbf{}<++><Esc>T{i
+autocmd FileType tex inoremap ;it \textit{}<++><Esc>T{i
+
+" beamer macros
+autocmd FileType tex inoremap ;fr \begin{frame}<CR>\frametitle{}<CR><++><CR>\end{frame}<Esc>kklli
+
+" book macros
+autocmd FileType tex inoremap ;sw \switchcolumn[]<++><Esc>4hi
+
+" preambule macros
+autocmd FileType tex inoremap ;up \usepackage{}<Esc>i
+autocmd FileType tex inoremap ;hy \hyphenation{}<Esc>i
+
+" apacite style
+autocmd FileType tex inoremap ;ap \bibliographystyle{apacite}<CR>\bibliography{}<Esc>i
+""" END latex macros
+
+" make background transparent
+"hi Normal ctermbg=none
+"hi NonText ctermbg=none
+
+" disalbe automatic identation
+filetype indent off
+
+" disable automatic comment
+autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o
+
+" clear a TeX build after exiting vim
+autocmd VimLeavePre *.tex !texclear "%"
+autocmd VimLeavePre *.md !texclear "%"
+autocmd VimLeavePre *.c !rm -rf .ccls-cache
+autocmd VimLeavePre *.cc !rm -rf .ccls-cache
+autocmd VimLeavePre *.cpp !rm -rf .ccls-cache
+autocmd VimLeavePre *.h !rm -rf .ccls-cache
+autocmd VimLeavePre *.hh !rm -rf .ccls-cache
+
+Plug 'kien/rainbow_parentheses.vim'
+Plug 'vim-python/python-syntax'
+let g:python_highlight_all = 1
+
+" copy from / to clipboard
+vnoremap <C-c> "+y
+map <C-p> "+P
+
+" use TAB to autocomplete w/ coc
+inoremap <silent><expr> <TAB>
+      \ pumvisible() ? "\<C-n>" :
+      \ <SID>check_back_space() ? "\<TAB>" :
+      \ coc#refresh()
+inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"
+
+function! s:check_back_space() abort
+  let col = col('.') - 1
+  return !col || getline('.')[col - 1]  =~# '\s'
+endfunction
+
+" Use `:Format` to format current buffer
+command! -nargs=0 Format :call CocAction('format')
+
+" Add status line support, for integration with other plugin, checkout `:h coc-status`
+set statusline^=%{coc#status()}%{get(b:,'coc_current_function','')}
+
+" if hidden is not set, TextEdit might fail.
+set hidden
+
+" Better display for messages
+set cmdheight=2
+
+" You will have bad experience for diagnostic messages when it's default 4000.
+set updatetime=300
+
+" always show signcolumns
+set signcolumn=yes
+
+" Use <c-space> to trigger completion.
+inoremap <silent><expr> <c-space> coc#refresh()
+
+" Use `[g` and `]g` to navigate diagnostics
+nmap <silent> [g <Plug>(coc-diagnostic-prev)
+nmap <silent> ]g <Plug>(coc-diagnostic-next)
+
+" Remap keys for gotos
+nmap <silent> gd <Plug>(coc-definition)
+nmap <silent> gy <Plug>(coc-type-definition)
+nmap <silent> gi <Plug>(coc-implementation)
+nmap <silent> gr <Plug>(coc-references)
+
+set colorcolumn=80
+
+autocmd FileType plaintex,tex,latex syntax spell toplevel
+" Automatically wrap at 80 characters for Markdown
+" autocmd BufRead,BufNewFile *.md setlocal textwidth=80
+
+nmap <leader>rn <Plug>(coc-rename)
+
+vmap <leader>f  <Plug>(coc-format-selected)
+nmap <leader>f  <Plug>(coc-format-selected)
+function! MathAndLiquid()
+    "" Define certain regions
+    " Block math. Look for "$$[anything]$$"
+    syn region math start=/\$\$/ end=/\$\$/
+    " inline math. Look for "$[not $][anything]$"
+    syn match math_block '\$[^$].\{-}\$'
+
+    " Liquid single line. Look for "{%[anything]%}"
+    syn match liquid '{%.*%}'
+    " Liquid multiline. Look for "{%[anything]%}[anything]{%[anything]%}"
+    syn region highlight_block start='{% highlight .*%}' end='{%.*%}'
+    " Fenced code blocks, used in GitHub Flavored Markdown (GFM)
+    syn region highlight_block start='```' end='```'
+
+    "" Actually highlight those regions.
+    hi link math Statement
+    hi link liquid Statement
+    hi link highlight_block Function
+    hi link math_block Function
+endfunction
+
+" Call everytime we open a Markdown file
+autocmd BufRead,BufNewFile,BufEnter *.md,*.markdown call MathAndLiquid()
+Plug 'vim-pandoc/vim-pandoc-syntax'
+let g:vim_markdown_math = 1
+
+" Go to tab by number
+noremap <leader>1 1gt
+noremap <leader>2 2gt
+noremap <leader>3 3gt
+noremap <leader>4 4gt
+noremap <leader>5 5gt
+noremap <leader>6 6gt
+noremap <leader>7 7gt
+noremap <leader>8 8gt
+noremap <leader>9 9gt
+noremap <leader>0 :tablast<cr>
+
+set noshowmode

+ 85 - 0
dot-config/xbindkeys/config

@@ -0,0 +1,85 @@
+# toggle mute
+"amixer set Master toggle && pkill -RTMIN+1 dwmblocks"
+   XF86AudioMute
+"amixer set Master toggle && pkill -RTMIN+1 dwmblocks"
+   Mod4 + F1
+
+# lower volume
+"amixer set Master 10%- && pkill -RTMIN+1 dwmblocks"
+   XF86AudioLowerVolume
+"amixer set Master 10%- && pkill -RTMIN+1 dwmblocks"
+   Mod4 + F2
+
+# increase volume
+"amixer set Master 10%+ && pkill -RTMIN+1 dwmblocks"
+   XF86AudioRaiseVolume
+"amixer set Master 10%+ && pkill -RTMIN+1 dwmblocks"
+   Mod4 + F3
+
+# dmenu mount prompt
+"dmenumount"
+   Mod4 + F8
+
+# dmenu umount prompt
+"dmenuumount"
+   Mod4 + F9
+
+# decrease monitor brightness
+"dec-brightness && pkill -RTMIN+2 dwmblocks && brightness-save"
+   Mod4 + F11
+
+# increase monitor brightness
+"inc-brightness && pkill -RTMIN+2 dwmblocks && brightness-save"
+   Mod4 + F12
+
+# select area of screenshoot
+"screenshot-area"
+   Mod4 + Print
+
+# dmenu emoji selector
+"dmenuunicode"
+   Mod4 + E
+
+# command prompt (only non-root commands)
+"dmenuprompt"
+   Mod4 + R
+
+# force "reloading" dwm windows
+"st -e exit"
+   Mod4 + S
+
+# dmenu greek letters prompt
+"dmenu-greek-letters-prompt"
+   Mod4 + G
+
+# open chromium
+"chromium"
+   Mod4 + V
+
+# make a screenshot of the full screen
+"screenshot"
+   Print
+
+# toggle picom
+"toggle-picom"
+   Mod4 + W
+
+# open stream copied to clip board in mpv
+"open-stream"
+   Mod4 + O
+
+# open gui file manager
+"pcmanfm"
+   Mod4 + A
+
+# open newsboat in new terminal window
+"st-exec newsboat"
+   Mod4 + U
+
+# open neomutt in new terminal window
+"st-exec neomutt"
+   Mod4 + Z
+
+# open htop in new terminal window
+"st-exec htop"
+   Mod4 + F7

+ 81 - 0
dot-config/zsh/.zshrc

@@ -0,0 +1,81 @@
+# Enable colors and change prompt:
+autoload -U colors && colors
+PS1="%B%{$fg[red]%}[%{$fg[yellow]%}%n%{$fg[green]%}@%{$fg[blue]%}%M %{$fg[magenta]%}%~%{$fg[red]%}]%{$reset_color%}$%b "
+
+# History in cache directory:
+HISTSIZE=10000
+SAVEHIST=10000
+HISTFILE=~/.cache/zsh/history
+
+# Basic auto/tab complete:
+autoload -U compinit
+zstyle ':completion:*' menu select
+zmodload zsh/complist
+compinit
+_comp_options+=(globdots)		# Include hidden files.
+
+# vi mode
+bindkey -v
+export KEYTIMEOUT=1
+
+# Use vim keys in tab complete menu:
+bindkey -M menuselect 'h' vi-backward-char
+bindkey -M menuselect 'k' vi-up-line-or-history
+bindkey -M menuselect 'l' vi-forward-char
+bindkey -M menuselect 'j' vi-down-line-or-history
+bindkey -v '^?' backward-delete-char
+
+# Change cursor shape for different vi modes.
+function zle-keymap-select {
+  if [[ ${KEYMAP} == vicmd ]] ||
+     [[ $1 = 'block' ]]; then
+    echo -ne '\e[1 q'
+  elif [[ ${KEYMAP} == main ]] ||
+       [[ ${KEYMAP} == viins ]] ||
+       [[ ${KEYMAP} = '' ]] ||
+       [[ $1 = 'beam' ]]; then
+    echo -ne '\e[5 q'
+  fi
+}
+zle -N zle-keymap-select
+zle-line-init() {
+    zle -K viins # initiate `vi insert` as keymap (can be removed if `bindkey -V` has been set elsewhere)
+    echo -ne "\e[5 q"
+}
+zle -N zle-line-init
+echo -ne '\e[5 q' # Use beam shape cursor on startup.
+preexec() { echo -ne '\e[5 q' ;} # Use beam shape cursor for each new prompt.
+
+# Use lf to switch directories and bind it to ctrl-o
+lfcd () {
+    tmp="$(mktemp)"
+    lf -last-dir-path="$tmp" "$@"
+    if [ -f "$tmp" ]; then
+        dir="$(cat "$tmp")"
+        rm -f "$tmp"
+        [ -d "$dir" ] && [ "$dir" != "$(pwd)" ] && cd "$dir"
+    fi
+}
+bindkey -s '^o' 'lfcd\n'
+
+# Edit line in vim with ctrl-e:
+autoload edit-command-line; zle -N edit-command-line
+bindkey '^e' edit-command-line
+
+# Load aliases and shortcuts if existent.
+[ -f "$HOME/.config/exportrc" ] && source "$HOME/.config/exportrc"
+[ -f "$HOME/.config/aliasrc" ] && source "$HOME/.config/aliasrc"
+
+if echo $USER | grep -q "miner"; then
+    if cat /tmp/norisa/currently-mining | grep -q "0"; then
+        echo "Start mining ..."
+        echo "1" > /tmp/norisa/currently-mining
+        nmine start
+    fi
+fi
+
+# fish-like zsh autosuggestions
+source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
+
+# Load zsh-syntax-highlighting; should be last.
+source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh 2>/dev/null

+ 24 - 0
local-bin/addpushremote

@@ -0,0 +1,24 @@
+#!/bin/sh
+
+[ -z "$1" ] && echo "Error: no argument given" && exit 1
+
+git pull || exit 1
+
+fetch="$(git remote -v | grep fetch | awk '{print $2}')"
+reponame="$(echo "$fetch" | sed 's/^.*\///; s/\..*$//')"
+newpushremote="$(echo "$1" | sed "s/REPONAME/$reponame/")"
+
+if ! git remote -v | grep -q "$newpushremote"; then
+    printf "\nAdding new push remote ...\n\n"
+    git remote set-url origin --add --push "$newpushremote"
+fi
+
+if ! git remote -v | grep push | grep -q "$fetch" ; then
+    echo "Readding fetch remote to push ...\n"
+    git remote set-url origin --add --push "$fetch"
+fi
+
+git push
+
+printf "\nShowing remotes ...\n\n"
+git remote -v

+ 12 - 0
local-bin/automine-toggle

@@ -0,0 +1,12 @@
+#!/bin/sh
+
+if cat "/etc/systemd/system/getty@tty1.service.d/override.conf" | grep -q "\-\-autologin"; then
+    echo "Disabling automining ...";
+    sudo rm -rf "/etc/systemd/system/getty@tty1.service.d"
+    #sudo mkdir -p "/etc/systemd/system/getty@tty1.service.d"
+    #printf "[Service]\nExecStart=\nExecStart=\nType=idle" | sudo tee "/etc/systemd/system/getty@tty1.service.d/override.conf"
+else
+    echo "Enabling automining ..."
+    sudo mkdir -p "/etc/systemd/system/getty@tty1.service.d"
+    printf "[Service]\nExecStart=\nExecStart=-/sbin/agetty --noissue --autologin miner %%I \$TERM\nType=idle" | sudo tee "/etc/systemd/system/getty@tty1.service.d/override.conf"
+fi

+ 15 - 0
local-bin/battery

@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# script to display the battery state in dwmblocks
+
+acpi -b | grep -q "Battery 0" || { printf ""; exit; }
+
+BATTERYSTATE=$( acpi -b | awk '{ split($5,a,":"); print substr($3,0,2), $4, "["a[1]":"a[2]"]" }' | tr -d ',DiFu' )
+if [[ $BATTERYSTATE =~ "Ch" ]]
+then
+    icon="⚡"
+else
+    icon="🔋"
+fi
+batterypercent=$(echo "$BATTERYSTATE" | tr -d 'Ch' | sed 's/cargng:/?/')
+printf "%s%s\\n" "$icon" "$batterypercent"

+ 8 - 0
local-bin/brightness

@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# script to display the brightness state in dwmblocks
+
+device=$(brightnessctl -l | grep "class 'backlight'" | head -n 1 | awk '{print $2}' | tr -d "'")
+[ -z "$device" ] && { printf ""; exit; }
+
+printf "🔆 %s\\n" "$(brightnessctl -d "${device}" | grep Current | awk -F '[)(]' '{print $2}')"

+ 8 - 0
local-bin/brightness-save

@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# script to save the brightness state so it is the same after a restart
+
+device=$(brightnessctl -l | grep "class 'backlight'" | head -n 1 | awk '{print $2}' | tr -d "'")
+[ -z "$device" ] && { printf ""; exit; }
+
+printf "%s\\n" "$(brightnessctl -d "${device}" | grep Current | awk -F '[)(]' '{print $2}' | tr -d "%")" > ~/.config/norisa/brightness-state

+ 123 - 0
local-bin/bv

@@ -0,0 +1,123 @@
+#!/bin/sh
+
+# bv, short for bible verse, is a simple program for helping to learn and 
+# remember bible verses from a minimal X environment and the command line.
+
+# make sure needed dirs exist
+conf="${XDG_CONFIG_DIR:-$HOME/.config}/bv"
+cache="${XDG_CACHE_DIR:-$HOME/.cache}/bv"
+[ -d "$conf" ] || mkdir -p "$conf"
+[ -d "$cache" ] || mkdir -p "$cache"
+
+
+help_msg() {
+    printf "Usage:\\n\
+ -s \t set new bible verse to given string or path to file\\n\
+ -l \t list current bible verse \\n\
+ -u \t update media (do this after changing your wallpaper)\\n\
+ -a \t ask for bible verse via stdin and mark mistakes if found\\n\
+ -h \t show this help message\\n"
+}
+
+generate_assets() {
+    # fetch infos
+    bgpath="$(tail -n 1 "${XDG_CACHE_DIR:-$HOME/.cache}/.fehbg" | rev | \
+        awk '{print $1}' | rev | sed 's/.$//;s/^.//' )"
+    dim="$(mediainfo "$bgpath" | grep "Width\|Height" | sed 's/^.*\: //;s/pixels//' \
+        | tr -d ' ' | tr '\n' x | sed s'/x$/\n/')"
+    width="$(echo "$dim" | sed 's/x.*//')"
+    #height="$(echo "$dim" | sed 's/.*x//')"
+    bgext="${bgpath##*.}"
+    savedpath="$(cat "$cache/bg-orig.path")"
+    savedext="${savedpath##*.}"
+
+    # clunky path parsing ...
+
+    [ -f "$cache/bg-orig.path" ] || echo "$bgpath" > "$cache/bg-orig.path"
+
+    if ! echo "${bgpath##*/}" | grep -q "bv-bg.png"; then
+        echo "$bgpath" > "$cache/bg-orig.path"
+    fi
+
+    echo "$savedpath" | grep -q "bv-bg.png" && savedpath=""
+
+    if [ ! -s "$savedpath" ]; then
+        if [ -n "$savedpath" ]; then
+            cp "$cache/bg-orig.$savedext" "$savedpath" && 
+            echo "original file moved or deleted: restoring ..."
+        fi
+    fi
+
+    # check if new background should be generated
+    if diff "$cache/bg-orig.$savedext" "$(cat "$cache/bg-orig.path")" > /dev/null 2> /dev/null &&
+        diff "$cache/verse" "$conf/verse" > /dev/null 2> /dev/null; then
+        echo "Everything already up to date, skipping Asset Generation ..."
+    else
+        # cache new bg incl. its source path
+        cp "$bgpath" "$cache/bg-orig.$bgext"
+        echo "$bgpath" > "$cache/bg-orig.path"
+
+        # cache new verse
+        cat "$conf/verse" > "$cache/verse"
+
+        echo "Generating Background ..."
+
+        # calculate text scaling accordingly to the resolution
+        : $((scal = width / 128))
+        : $((dens = 300 * 15 / scal))
+        : $((pntr = scal * scal * 16 / 225))
+        : $((strk = scal * 2 / 15))
+
+        # generate text and merge w/ background
+        magick -gravity center -background transparent -density "$dens" \
+            -pointsize "$pntr" -fill white -size "$dim" -stroke black -strokewidth "$strk" \
+            -font "/usr/share/fonts/adobe-source-code-pro/SourceCodePro-BlackIt.otf" \
+            caption:@- "$cache/bv-verse.png" < "$conf/verse"
+        composite -gravity center "$cache/bv-verse.png" \
+            "$bgpath" "$cache/bv-bg.png"
+    fi
+}
+
+update_assets() {
+    # set bg
+    echo "Setting Background ..."
+    feh --bg-scale "$cache/bv-bg.png"
+    mv "$HOME/.fehbg" "${XDG_CACHE_DIR:-$HOME/.cache}"
+}
+
+exit_when_no_verse() {
+    [ ! -s "$conf/verse" ] && echo "Error: No bible verse set." && exit 1
+}
+
+verse_diff() {
+    git -c color.diff.new='bold reverse green' \
+        -c color.diff.old='bold reverse red' diff --no-index -U0 --no-color \
+        --word-diff=color --word-diff-regex=. \
+        "$cache/guessed-verse" "$cache/stripped-verse" | tail -n +3 |
+        grep -v '\-\-\-\|+++'
+}
+
+# parse arguments
+while getopts ":s:ahlu" option; do case "${option}" in
+    h)  help_msg; exit 0;;
+    s)  newbv="${OPTARG}"
+        if [ -s "$newbv" ]; then
+            cat "$newbv" > "$conf/verse"
+            cp "$conf/verse" "$cache/verse"
+        elif [ -n "$newbv" ]; then
+            echo "$newbv" > "$conf/verse"
+            cp "$conf/verse" "$cache/verse"
+        fi
+
+        generate_assets; update_assets; exit 0;;
+    l)  exit_when_no_verse; cat "$conf/verse"; exit 0;;
+    u)  generate_assets; update_assets; exit 0;;
+    a)  exit_when_no_verse; printf "bible verse: "; read -r ask_input
+        echo "$ask_input" > "$cache/guessed-verse"
+        tr '\n' ' ' < "$conf/verse" | sed 's/.$/\n/; s/  / /g' > "$cache/stripped-verse"
+        verse_diff; exit 0;;
+    *)  printf "Invalid option: -%s\\n\\n" "$OPTARG"; help_msg; exit 1 ;;
+esac done
+
+# when no arguments are given, print help message
+help_msg

+ 22 - 0
local-bin/compile

@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# script to compile some document types
+
+[ -z "$1" ] && { echo "Error: Usage: compile [filename]"; exit 1; }
+
+choosepandoc() {
+    [ -z "$template" ] && template="$(ls $HOME/.config/setup/templates/pandoc/* | \
+        sed 's/.*\///g' | dmenu -i -l 30 -p "choose pandoc template: ")"
+    [ -z "$newext" ] && newext="$(echo "$template" | sed 's/.*\.//; s/latex/pdf/;')"
+}
+
+base=${1%.*}
+ext=${1##*.}
+
+case "$ext" in
+    ms) preconv "$1" |  groff -"$ext" -dpaper=a4 -P -pa4 -T pdf > "$base.pdf" && pkill -HUP mupdf;;
+    tex) pdflatex "$1"; pkill -HUP mupdf;;
+    md) choosepandoc; pandoc -V "fontsize=16pt" -s "$1" --template="$HOME/.config/setup/templates/pandoc/$template" -V "fontsize=16pt" -o "$base.$newext"; pkill -HUP mupdf;;
+    rmd) pandoc -s "$1" --template="$HOME/.config/setup/templates/pandoc/german.latex" -o "$base.pdf"; pkill -HUP mupdf;;
+    *) echo "Error: unknown file extension '$ext'"; exit 1;#;
+esac

+ 8 - 0
local-bin/dec-brightness

@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# script to decrease the brightness by 10%
+
+device=$(brightnessctl -l | grep "class 'backlight'" | head -n 1 | awk '{print $2}' | tr -d "'")
+brightness=$(brightnessctl -d "${device}" | grep Current | awk -F '[)(]' '{print $2 - 10}')
+
+brightnessctl -d "${device}" set "$brightness"%

+ 14 - 0
local-bin/dmenu-greek-letters-prompt

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# script to get a selection of greek letters using dmenu
+
+selected=$(dmenu -l 25 < ~/.local/share/norisa/greek-letters)
+
+# exit if none selected
+[ -z "$selected" ] && exit
+
+# copies the selected letter in the desired format
+case "${1##-}" in
+	vim) echo "\\${selected##* }" | tr -d '\n' | xclip -selection clipboard ;;
+	*) echo "${selected%% *}" | tr -d '\n' | xclip -selection clipboard ;;
+esac

+ 11 - 0
local-bin/dmenu-java

@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# script to change the java environment using dmenu from the commandline
+
+env="$(archlinux-java status | grep java | dmenu -l 30)"
+
+# exit if none selected
+[ -z "$env" ] && exit
+
+# set new environment
+sudo archlinux-java set "$env"

+ 68 - 0
local-bin/dmenumount

@@ -0,0 +1,68 @@
+#!/bin/sh
+
+# Gives a 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 existsing directories. If you
+# input a novel directory, it will prompt you to create that directory.
+# Note that I copied this script from Luke Smith
+
+getmount() { \
+	[ -z "$chosen" ] && exit 1
+        # shellcheck disable=SC2086
+	mp="$(find /mnt 2>/dev/null | dmenu -i -p "Type in mount point.")" || exit 1
+	[ "$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' | grep -v 'sda1' | 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

+ 5 - 0
local-bin/dmenuprompt

@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# script to get a prompt for power options or entering any other command
+
+printf 'lock\nbetterlockscreen -l\nsdn\nreboot' | dmenu -p '$' | tee /tmp/prompt-cmd | xargs -0 zsh -ic

+ 44 - 0
local-bin/dmenuumount

@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# A dmenu prompt to unmount drives. (copied from Luke Smith)
+# 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

+ 11 - 0
local-bin/dmenuunicode

@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# The famous "get a menu of emojis to copy" script. (copied from Luke Smith)
+
+# get user selection via dmenu from emoji file.
+chosen=$(cut -d ';' -f1 ~/.local/share/norisa/emoji | dmenu -i -l 30 | sed "s/ .*//")
+
+# exit if none chosen.
+[ -z "$chosen" ] && exit
+
+echo "$chosen" | tr -d '\n' | xclip -selection clipboard

+ 23 - 0
local-bin/dyt

@@ -0,0 +1,23 @@
+#!/bin/sh
+
+search="$(printf "" | dmenu -p "Search Query: " | tr ' ' '+')"
+
+curl "https://www.youtube.com/results?search_query=$search" > "/tmp/answer.html"
+
+titles="$(grep "watch?v=" "/tmp/answer.html" | tr ',' '\n'  | grep "^\"title\":{\"runs\":" | grep "\"}]" | sed 's/"}]}$//g; s/"}]$//g; s/.*\":\"//g;' | head -n 20)"
+
+urls="$(grep "watch?v=" /tmp/answer.html | tr ',' '\n' | grep "watch?v=" | uniq | sed s'/\"$//g; s/.*?v=//g;' | head -n 20)"
+
+
+i=0; j=20
+echo "" > "/tmp/dyt"
+while [ "$i" -lt "$j" ]; do
+    : $((i = i + 1))
+    currentURL="$(echo "$urls" | sed -n "${i}p")" 
+    currentTITLE="$(echo "$titles" | sed -n "${i}p")" 
+    echo "$currentTITLE   ---   $currentURL" >> "/tmp/dyt"
+done
+
+chosen="$(dmenu -i -l 20 < "/tmp/dyt" | sed 's/.*   ---   //;')"
+
+open-stream "https://www.youtube.com/watch?v=$chosen"

+ 6 - 0
local-bin/fcp

@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# fast copy program (faster than "cp", but copies ALL data incl. permissions)
+# note that this only works with directorys as of now
+
+(cd "$1" || exit; tar -cf - .) | (cd "$2" || exit; tar -xf -)

+ 20 - 0
local-bin/fetch-file-with-link

@@ -0,0 +1,20 @@
+#!/bin/sh
+
+while getopts ":c:l:o:h" option; do case "${option}" in
+    h) printf "Usage (note that c,l and o flags are obligatory):\\n\
+ -c [filename]\t path to cookie file (.txt file) \\n -l [filename]\t link \
+to the file on sharepoint (full url)\\n\
+ -o [path]\t path to output directory\\n\\n\
+ -h\t\t show this help message\\n" && exit 1 ;;
+    c) cookiefile=${OPTARG};;
+    l) linktofile=${OPTARG};;
+    o) outputpath=${OPTARG};;
+    *) printf "Invalid option: -%s\\n" "$OPTARG" && exit 1 ;;
+esac done
+
+[ ! -f "$cookiefile" ] && echo "Error: file '$cookiefile' not found" && exit 1
+[ ! -d "$outputpath" ] && echo "Error: path '$outputpath' not found" && exit 1
+[ -z "$linktofile" ] && echo "Error: no link provided" && exit 1
+
+# note: '--no-if-modified-since' was suggested by wget on running with out it
+wget -nH --cut-dirs=1 --quiet -P "$outputpath" --cookies=on --load-cookies "$cookiefile" --keep-session-cookies --no-check-certificate --no-if-modified-since -m "$linktofile"

+ 5 - 0
local-bin/fixitunes

@@ -0,0 +1,5 @@
+#!/bin/bash
+
+# fix weird audio duration in iTunes
+
+for f in *.mp3; do ffmpeg -i "$f" -acodec copy "${f%.*}-fix.mp3"; mv "${f%.*}-fix.mp3" "$f"; done

+ 21 - 0
local-bin/fnc

@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# File Naming Correction (script)
+# Usage: fnc [filename]
+
+[ ! -f "$1" ] && { echo "Error: File '$1' not found"; exit 1; }
+
+file="${1##*/}"
+dir="${1%/*}"
+
+# lowercase
+base=$(echo "${file%.*}" | tr '[:upper:]' '[:lower:]')
+ext=$(echo "$file" | grep -q "\." && 
+    echo ".${file##*.}" | tr '[:upper:]' '[:lower:]')
+
+# replace whitespaces with single dashes
+base=$(echo "$base" | sed 's/\s/-/g;' | tr -s - - |
+    # lowercase first letter
+    awk '{printf tolower(substr($0,1,1))} {print substr($0,2)}') 
+
+mv -i "$dir/$file" "$dir/$base$ext"

+ 5 - 0
local-bin/force-upstate

@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ -z "$1" ] && exit 1
+
+sudo ip link set "$1" mode default

+ 17 - 0
local-bin/furryfox

@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# wrapper script to move the ~/.mozilla folder after exiting firefox
+
+# check if firefox is installed
+command -v "firefox" > /dev/null || exit 1
+
+# make sure datadir exists
+datadir=${XDG_DATA_HOME:-$HOME/.local/share}/furryfox
+[ -d "$datadir" ] || mkdir -p "$datadir" || exit 1
+
+# mv datadir when needed and start firefox
+[ ! -d "$datadir/.mozilla" ] || mv "$datadir/.mozilla" "$HOME/.mozilla"
+firefox
+
+# move mozilla folder after closing firefox
+mv "$HOME/.mozilla" "$datadir"

+ 6 - 0
local-bin/get-date

@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# script to display the brightness state in dwmblocks
+
+DATETIME=$(date +"📅 %d.%m.%y ⌚ %H:%M")
+printf "%s \\n" "$DATETIME" 

+ 12 - 0
local-bin/get-single-token

@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# This is a shell script to get the binary (in hex format)
+# from a file created on the TI-84 that contains a single 
+# token. This is to add new tokens very quick and easy.
+
+# Note: Sometimes a token only uses only one binary, but
+# sometimes two. Be careful about that.
+
+[ -z "$*" ] && echo "Error: No Arguments provided" && exit 1
+od -A x -t x1z -v "$1"
+od -A x -t x1z -v "$1" | awk '{if(NR==5) print $12 " " $13}'

+ 6 - 0
local-bin/get-uptime

@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# script do display the uptime in dwmblocks
+
+UPTIME=$(uptime | sed 's/.*up\s*//' | sed 's/,\s*[0-9]* user.*//' | sed 's/  / /g')
+printf "%s %s\\n" "Up" "$UPTIME"

+ 12 - 0
local-bin/get-volume

@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# script to display the current volume and mute state in dwmblocks
+
+volume=$(amixer sget Master | grep 'Front Left:' | awk -F '[\\]\\[]' '{print $2}')
+if [ -z "$(amixer sget Master | grep "off" )" ];
+then
+    muteicon="🔊"
+else
+    muteicon="🔇"
+fi
+printf "%s %s\\n" "$muteicon" "$volume"

+ 20 - 0
local-bin/getnzz

@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+from selenium import webdriver
+from selenium.webdriver.chrome.options import Options
+from sys import argv
+
+options = webdriver.ChromeOptions()
+options.add_extension(argv[1])
+options.add_extension(argv[2])
+try:
+    driver = webdriver.Chrome(options=options)
+except:
+    print("Error: Could not connect to webdriver")
+    exit(1)
+
+driver.get(argv[3])
+with open(argv[4], "w") as f:
+    f.write(driver.page_source)
+f.close()
+driver.quit()

+ 7 - 0
local-bin/gid

@@ -0,0 +1,7 @@
+#!/bin/sh
+
+ git -c color.diff.new='bold reverse green' \
+    -c color.diff.old='bold reverse red' diff --no-index -U0 --no-color \
+    --word-diff=color --word-diff-regex=. \
+    $HOME/.cache/bv/guessed-verse $HOME/.cache/bv/stripped-verse | tail -n +3 |
+    grep -v '\-\-\-\|+++'

+ 67 - 0
local-bin/gkg-connect

@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# script to connect to weird wifis
+
+# make sure that script is run with root privileges
+[ $EUID -ne 0 ] && { echo -e "\e[0;30;101m Error: Please run this script with root privileges \e[0m"; exit; }
+
+# list network interfaces
+echo -e "\e[0;30;42m List of Wifi interfaces (iwconfig): \e[0m\n"
+iwconfig
+
+# get user input
+echo -e "\e[0;30;46m Select Wifi Interface: \e[0m" 
+read -rp " >>> " interface
+
+echo -e "\n\e[0;30;46m Username: \e[0m" 
+read -rp " >>> " username
+
+echo -e "\n\e[0;30;46m Password: \e[0m" 
+echo -n " >>> "
+read -rs password
+printf "\n"
+
+# define unique uuid
+uuid=$(uuidgen)
+while grep -q "uuid=${uuid}" /etc/NetworkManager/system-connections/*
+do
+    uuid=$(uuidgen)
+done
+
+# generate connection file
+printf "[connection]
+id=GKGe
+uuid=%s
+type=wifi
+interface-name=%s
+permissions=
+
+[wifi]
+mac-address-blacklist=
+mode=infrastructure
+ssid=GKGe
+
+[wifi-security]
+auth-alg=open
+key-mgmt=wpa-eap
+
+[802-1x]
+eap=peap;
+identity=%s
+password=%s
+phase2-auth=mschapv2
+
+[ipv4]
+dns-search=
+method=auto
+
+[ipv6]
+addr-gen-mode=stable-privacy
+dns-search=
+method=auto
+
+[proxy]
+" "$uuid" "$interface" "$username" "$password" > /etc/NetworkManager/system-connections/gkg-connect.nmconnection
+chmod 600 /etc/NetworkManager/system-connections/gkg-connect.nmconnection
+systemctl restart NetworkManager || rc-service NetworkManager restart
+nmcli connection up GKGe

+ 9 - 0
local-bin/glosscompile

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+[ -z "$1" ] && { echo "Error: Usage: glosscompile [filename]"; exit 1; }
+
+[ ! -f "$1" ] && exit 1
+
+base=${1%.*}
+
+makeglossaries "${base}.glo"

+ 8 - 0
local-bin/inc-brightness

@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# script to increase the brightness by 10%
+
+device=$(brightnessctl -l | grep "class 'backlight'" | head -n 1 | awk '{print $2}' | tr -d "'")
+brightness=$(brightnessctl -d "${device}" | grep Current | awk -F '[)(]' '{print $2 + 10}')
+
+brightnessctl -d "${device}" set "$brightness"%

+ 5 - 0
local-bin/internal-ip

@@ -0,0 +1,5 @@
+#!/bin/sh
+
+# script to display the internal ip of the current connected network
+
+ip a | grep "inet 192" | tr '/' ' ' | awk '{print $2}'

+ 32 - 0
local-bin/internet

@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# script to display the network state in dwmblocks
+
+wifi=$(iwgetid -r)
+upstate=$(ip a | grep BROADCAST,MULTICAST, | awk '{print $9}')
+if [ -z "$wifi" ];
+    then
+        printf "%s\\n" "🔌 $upstate"
+    else
+        # alternatively: diplay percentage
+        # awk '/^\s*w/ { print "📶", int($3 * 100 / 70) "%" }' \
+        # /proc/net/wireless | sed 's/100/99/'
+
+		percent=$(awk '/^\s*w/ { print int($3 * 100 / 70) }' \
+                  /proc/net/wireless | head -n 1)
+		if [ "$percent" -gt 80 ];
+		then
+			echo "🟩🟩🟩🟩🟩"
+		elif [ "$percent" -gt 60 ];
+		then
+			echo "🟩🟩🟩🟩🟧"
+		elif [ "$percent" -gt 40 ];
+		then
+			echo "🟩🟩🟩🟧🟧"
+		elif [ "$percent" -gt 20 ];
+		then
+			echo "🟩🟩🟧🟧🟧"
+		else
+			echo "🟩🟧🟧🟧🟧"
+		fi
+    fi

+ 7 - 0
local-bin/list-mouses

@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# list all connected mouses
+
+xinput | grep -B1000 "Virtual core keyboard" | preconv | cut -d' ' -f5-  |\
+sed '$ d; /^$/d;' | grep -v "master pointer" | rev | cut -d' ' -f5- | rev |\
+sed 's/\[slave//g;' | tr '\t' '    '

+ 9 - 0
local-bin/low-battery-power-shutdown

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# script to shutdown the pc normally when running critical on battery
+
+percent=$(acpi -b | awk '{print($4)}'| tr -d '%,')
+[ "$percent" -lt 10 ]; && echo "hi"
+#if [ "$percent" -lt 10 ]; then
+    #echo "$percent"
+#fi

+ 11 - 0
local-bin/mal-comment-scraper

@@ -0,0 +1,11 @@
+#!/bin/sh
+
+clipboard=$(xclip -out -sel clip | sed 's/!/\\!/')
+
+curl "$clipboard" > "/tmp/index.html"
+
+sed -i '0,/<h2>Reviews<\/h2>/d;' "/tmp/index.html"
+sed -i '0,/<h2>Recent News<\/h2>/!d;' "/tmp/index.html"
+sed -i '0,/<h2>Recommendations/!d;' "/tmp/index.html"
+pandoc -s "/tmp/index.html" -o "/tmp/index.pdf" --template="$HOME/.config/setup/templates/pandoc/english.latex"
+devour llpp "/tmp/index.pdf"

+ 67 - 0
local-bin/memeatlas-sync

@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# constants
+conf="${XDG_CONFIG_DIR:-$HOME/.config}/memeatlas-sync"
+cache="${XDG_CACHE_DIR:-$HOME/.cache}/memeatlas-sync"
+base_url="https://www.memeatlas.com/"
+ex_base_url="https:\/\/www.memeatlas.com\/"
+oldindex="none"
+
+# check dependencies
+for prog in jq wget; do
+	! command -v "$prog" > /dev/null && 
+        echo "Error: Program '$prog' not found." && exit 1
+done
+
+error() {
+    echo "Error: $@" && exit 1
+}
+
+
+# make sure needed dirs exist
+[ -d "$conf" ] || mkdir -p "$conf" || error "Could not create config directory"
+[ -d "$cache" ] || mkdir -p "$cache" || error "Could not create cache directory"
+
+# get dest dir
+[ -f "$conf/config" ] || error "No config file found"
+dest="$(cat "$conf/config")"
+# TODO: check $dest and s/~/$HOME/
+
+
+echo "Fetching Index ..."
+
+[ -f "$cache/index" ] && mv "$cache/index" "$cache/index.old" && oldindex=
+[ -f "$cache/index.html" ] && rm "$cache/index.html"
+wget -q --show-progress -P "$cache" "$base_url"
+categories="$(sed '0,/index.html/d; 0,/contact/!d' "$conf/index.html" | \
+    head -n -1 | sed 's/^.*href="//; s/.html.*$//')"
+for c in $categories; do
+    [ -f "$cache/$c.html" ] && rm "$cache/$c.html"
+done
+echo "$categories" | sed "s/^/$ex_base_url/; s/$/.html/" | wget -q --show-progress -P "$cache" -i -
+
+printf "\nGenerating Index ...\n"
+
+# generate new index
+for c in $categories; do
+    sed '0,/id="list/d; /flexListItem/!d; s/^.*href="//; s/".*$//' \
+        "$cache/$c.html" >> "$cache/index"
+done
+
+# check what files are new, create download list
+if [ -z "$oldindex" ]; then
+    [ -f "$cache/dl" ] && rm "$cache/dl"
+    while IFS='' read -r line; do
+        grep -q "$line" "$cache/index.old" || echo "$line" >> "$cache/dl"
+    done < "$cache/index"
+else
+    cp "$cache/index" "$cache/dl"
+fi
+
+if [ ! -f "$cache/dl" ]; then
+    printf "\nDownloading Skipped, already up-to-date...\n"
+else
+    printf "\nDownloading Images...\n"
+        sed "s/^/$ex_base_url/;" "$cache/dl" | \
+            wget -q --show-progress -P "$dest" -i -
+fi

+ 16 - 0
local-bin/mkjar

@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# create initial jar
+[ -z "$2" ] && echo "Error: missing arguments" && exit 1
+jar cvf "$@" || exit 1
+
+# open MANIFEST file template in $EDITOR
+printf "Class-Path: \nMain-Class: \n" > '/tmp/MANIFEST.MF'
+[ -z "$EDITOR" ] && echo "Error: \$EDITOR not set" && exit 1
+$EDITOR '/tmp/MANIFEST.MF'
+
+# apply manifest to jar
+jar uvfm "$1" '/tmp/MANIFEST.MF'
+
+# remove temporary files
+rm '/tmp/MANIFEST.MF'

+ 17 - 0
local-bin/mouse-acceleration

@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Script to Disable Mouse Acceleration (for dwm)
+
+# dmenu prompt to select the right device (using xorg-xinput)
+deviceID=$(xinput | grep -B1000 "Virtual core keyboard" | preconv | cut -d' ' -f5-  |\
+sed '$ d; /^$/d;' | grep -v "master pointer" | rev | cut -d' ' -f5- | rev |\
+sed 's/\[slave//g;' | tr '\t' '    ' | dmenu -i -l 30 | awk '{print $NF}' | sed 's/id=//g')
+
+[ -z "$deviceID" ] && exit 1
+
+# disable the mouse acceleration (using xorg-xinput)
+xinput --set-prop "$deviceID" 'libinput Accel Speed' 0
+xinput --set-prop "$deviceID" 'libinput Accel Profile Enabled' 0, 1
+
+# set the mouse speed (using xorg-xset)
+xset mouse 1 0 &

+ 3 - 0
local-bin/mp3pls

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+for f in *.opus *.m4a; do ffmpeg -i "$f" -c:a libmp3lame "${f%.*}.mp3" && rm -f "$f"; done

+ 75 - 0
local-bin/nmine

@@ -0,0 +1,75 @@
+#!/bin/sh
+
+[ ! -d "$HOME/.cache/nmine" ] && mkdir -p "$HOME/.cache/nmine"
+[ ! -f "$HOME/.cache/nmine/current-miner" ] && touch "$HOME/.cache/nmine/current-miner"
+cat "$HOME/.cache/nmine/current-miner" > /dev/null || { echo "Error: no access to cache file"; exit 1; }
+[ ! -d "$HOME/.config/nmine" ] && mkdir -p "$HOME/.config/nmine"
+[ ! -f "$HOME/.config/nmine/config" ] && touch "$HOME/.config/nmine/config"
+cat "$HOME/.config/nmine/config" > /dev/null || { echo "Error: no access to config file"; exit 1; }
+
+
+[ -z "$(cat "$HOME/.config/nmine/config")" ] && echo "Error: config file is empty" && exit 1
+
+helpMessage="Usage: nmine [option]
+Options:
+\tstart\t\tstart mining
+\tstop\t\tstop mining
+\tlist\t\tlist configured miners
+\tchange [miner]\tchange mining software / coin
+\thelp\t\tprint this help message"
+
+getMiners() {
+    grep "^miner" "$HOME/.config/nmine/config" | sed 's/^miner=//'
+}
+
+checkMinerConfig() {
+    getMiners | grep -q "^$miner\$" || { printf "Error: miner '%s' not found
+Exiting ...\n" "$miner"; exit 1; }
+}
+
+initCache () {
+    miner="$(cat "$HOME/.cache/nmine/current-miner")"
+    [ -z "$miner" ] && printf "Error: no miner selected, please run 'nmine change [miner]'\nExiting ...\n" && exit 1
+}
+
+
+
+[ -z "$1" ] && printf "Error: No Arguments given\n\n" && echo "$helpMessage" && exit 1
+
+case "$1" in
+    start)
+        echo "Start mining ..."
+        initCache
+        checkMinerConfig
+        cmd="$(grep -a1 "$miner" "$HOME/.config/nmine/config" | tail -n 1 | sed 's/^start=//')"
+        eval "$cmd";;
+    stop)
+        echo "Stop mining ..."
+        initCache
+        checkMinerConfig
+        processName="$(grep -a2 "$miner" "$HOME/.config/nmine/config" | tail -n 1 | sed 's/^stop=//')"
+        echo "$processName"
+        processID="$(pgrep -f "$processName")"
+        echo "$processID"
+        kill "$processID";;
+    list)
+        printf "Configured miners:\n"
+        miner="$(cat "$HOME/.cache/nmine/current-miner")"
+        [ -z "$miner" ] && getMiners && exit
+        getMiners | sed "s/$miner/$miner (current)/";;
+    change)
+        echo "Changing miner ..."
+        [ -z "$2" ] && printf "Error: Invalid Sytax\nExiting...\n" && exit
+        miner="$2"
+        checkMinerConfig
+        echo "$miner" > "$HOME/.cache/nmine/current-miner"
+        echo "Done";;
+    help)
+        echo "$helpMessage";;
+    *)
+        [ -z "$2" ] && printf "Error: Invalid Argument given:'%s'\n\n" "$1" &&
+        echo "$helpMessage" && exit 1
+
+        printf "Error: Invalid Arguments given:'%s'\n\n" "$@" &&
+        echo "$helpMessage" && exit 1
+esac

+ 36 - 0
local-bin/reapk

@@ -0,0 +1,36 @@
+#!/bin/zsh
+
+[ -f "$HOME/.config/norisa/reapk" ] || exit 1
+
+notify() {
+    echo "$1"
+    notify-send "ReAPK" "$1"
+}
+
+# check if access to file
+apkFile=$(cat "$HOME/.config/norisa/reapk")
+fileTest=$(file $apkFile)
+if echo $fileTest | grep -q "Error: cannot open APK file"; then 
+    notify "error"
+fi
+
+#select device
+
+deviceAmount=$(adb devices | wc -l)
+
+if [ "$deviceAmount" -lt 3 ]; then
+    notify "Error: cannot open any devices"
+    exit 1
+elif [ "$deviceAmount" -eq 3 ]; then
+    extraAPKoptions=""
+else
+    device=$(adb devices -l | sed '/List of devices/d; /^$/d' | dmenu -i -l 30 -p "Selet Device:" | awk '{print $1}')
+    if [ -z $device ]; then
+        notify "Error: no device selected"
+        exit 1
+    fi
+    extraAPKoptions="-s $device"
+fi
+
+# install and notify when action finished
+st-exec "adb install $extraAPKoptions -r $apkFile" && notify "Action Finished !!!"

+ 67 - 0
local-bin/redyt

@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# If notify-send is not found, use echo as notifier
+command -v "notify-send" > /dev/null && notifier="echo" || notifier="notify-send"
+
+# check dependencies
+for prog in dmenu jq nomacs wget curl; do
+	! command -v "$prog" > /dev/null && 
+        $notifier "redyt" "Error: Program '$prog' not found." && exit 1
+done
+
+# set dirs
+cachedir="${XDG_CACHE_HOME:-$HOME/.cache}/redyt"
+configdir="${XDG_CONFIG_HOME:-$HOME/.config}/redyt"
+
+# if dirs do not exist, create them
+[ ! -d "$cachedir" ] && mkdir -p "$cachedir"
+[ ! -d "$configdir" ] && mkdir -p "$configdir"
+
+# remove all cached images
+rm "${cachedir:?}"/*
+
+# set defaults
+defaultsub="memes"
+[ -f "$configdir/subreddits" ] || echo "$defaultsub" > "$configdir/subreddits"
+limit=100
+# select sorting (default: sort by hot)
+# sorting=$(printf "hot\nnew\n" | dmenu -p "Select Sorting" -i -l 10)
+# [ -z "$sorting" ] && 
+sorting="hot"
+
+# when no argument given, use dmenu to ask for subreddit
+if [ -z "$1" ]; then
+	subreddit=$(dmenu -p "Select Subreddit r/" -i -l 10 < \
+        "$configdir/subreddits" | cut -d\| -f1 | awk '{$1=$1;print}')
+
+	# if no subreddit was chosen, exit
+	[ -z "$subreddit" ] && exit 1
+else
+	subreddit="$1"
+fi
+
+
+# send a notification
+$notifier "Redyt" "📩 Downloading your 🖼️ Memes"
+
+# download the subreddit feed, containing only the first 100 entries (limit),
+# and store it inside $cachedir/tmp.json
+curl -H "User-agent: 'your bot 0.1'" \
+    "https://www.reddit.com/r/$subreddit/$sorting.json?limit=$limit" \
+    > "$cachedir/tmp.json"
+
+# get a list of images
+imgs="$(jq '.' < "$cachedir/tmp.json" | grep url_overridden_by_dest | \
+    grep -Eo "http(s|)://.*(jpg|png)\b" | sort -u)"
+
+# if there are no images, exit
+[ -z "$imgs" ] && $notifier "Redyt" \
+    "sadly, there are no images for subreddit $subreddit, " \
+    "please try again later!" && exit 1
+
+# set welcome img
+cp "$configdir/redyt.png" "$cachedir"
+
+# download + display images in cache dir
+wget -bq -P "$cachedir" "$imgs" > /dev/null 2> /dev/null
+devour nomacs "$cachedir/redyt.png" & #> /dev/null 2> /dev/null

+ 5 - 0
local-bin/rssyt

@@ -0,0 +1,5 @@
+#!/bin/sh
+
+[ -z "$1" ] && exit 1
+
+echo "https://www.youtube.com/feeds/videos.xml?channel_id=${1##*/}"

+ 62 - 0
local-bin/rsy

@@ -0,0 +1,62 @@
+#!/bin/bash
+
+configError() {
+    echo "Error: No valid configuration found, exiting"
+    notify-send "based-sync" "Error: No valid configuration found, exiting"
+    exit 1
+}
+
+# check dependencies
+for prog in internal-ip rsync nc notify-send; do
+    if ! command -v "$prog" > /dev/null 2>&1; then
+        echo "$prog is not detected" 1>&2
+        notify-send "$prog is not detected"; exit 1
+    fi
+done
+
+# set dirs
+configDir="${XDG_CONFIG_HOME:-$HOME/.config}"
+cacheFile="/tmp/norisa/based-sync-cache"
+
+# read config files
+[ -f "$HOME/.config/based-sync/dirs" ] || configError
+[ -f "$HOME/.config/based-sync/cons" ] || configError
+dirs="$(cat "$configDir/based-sync/dirs")"
+cons="$(grep -v "$(internal-ip)" < "$configDir/based-sync/cons")"
+
+# reset cachefile safely
+[ -d ${cacheFile%/*} ] || mkdir -p ${cacheFile%/*}
+if [ -f $cacheFile ]; then
+    rm $cacheFile; touch $cacheFile
+else
+    touch $cacheFile
+fi
+
+# check each connection via netcat
+for con in $cons; do
+    if nc -zv -w 1 "${con/*@}" 22 2>&1 | grep -q "succeeded"; then
+        echo "$con ON" | tee $cacheFile
+    else
+        echo "$con OFF"
+    fi
+done
+
+sed -i "s/ ON//g" $cacheFile
+
+# exit when no working connection found
+[ -s $cacheFile ] || configError
+
+# choose remote on which to sync the dirs to
+ip=$(dmenu -i -l 30 < $cacheFile)
+
+# sync dirs via rsync
+for dir in $dirs; do
+    remoteUser=${ip/@*}
+    rsync -uvrP --delete-after -e \
+        'ssh -T -c aes128-gcm@openssh.com -o Compression=no' \
+        "${dir/\~/$HOME}/" "$ip:${dir/\~/\/home\/$remoteUser}"
+done
+
+# success message
+echo "Success: File syncing is finished"
+notify-send "Success: File syncing is finished"

+ 11 - 0
local-bin/screencast-24

@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# record main display
+
+resolution=$(xrandr | grep '\*' | head -n 1 | awk '{print $1}')
+
+[ ! -d "$HOME/vids/screencasts" ] && mkdir -p "$HOME/vids/screencasts"
+
+ffmpeg -f x11grab -r 24 -s "$resolution" -i :0.0 -acodec acc -vcodec libx264 -crf 0 "$HOME/vids/screencasts/$(date +"%F--%H-%M-%S--%N").mkv" &
+
+notify-send "screencasting" "started"

+ 11 - 0
local-bin/screencast-60

@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# record main display
+
+resolution=$(xrandr | grep '\*' | head -n 1 | awk '{print $1}')
+
+[ ! -d "$HOME/vids/screencasts" ] && mkdir -p "$HOME/vids/screencasts"
+
+ffmpeg -f x11grab -r 60 -s "$resolution" -i :0.0 -acodec acc -vcodec libx264 -crf 0 "$HOME/vids/screencasts/$(date +"%F--%H-%M-%S--%N").mkv" &
+
+notify-send "screencasting" "started"

+ 7 - 0
local-bin/screenshot

@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# script to make a screenshot of the full screen area
+
+[ ! -d "$HOME/pix/screenshots" ] && mkdir-p "$HOME/pix/screenshots"
+
+import -windows root "pix/screenshots/$(date +"%F--%H-%M-%S--%N").jpg"

+ 7 - 0
local-bin/screenshot-area

@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# script to make a screenshot from the desired selection
+
+[ ! -d "$HOME/pix/screenshots" ] && mkdir -p "$HOME/pix/screenshots"
+
+import "pix/screenshots/$(date +"%F--%H-%M-%S--%N").jpg"

+ 24 - 0
local-bin/scripted-mouse-acceleration

@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# disable mouse acceleration with the device name given as an argument
+
+[ -z "$1" ] && exit 1
+
+sleep 5
+
+IDlist=$(xinput | grep -B1000 "Virtual core keyboard" | preconv | cut -d' ' -f5-  |\
+sed '$ d; /^$/d;' | grep -v "master pointer" | rev | cut -d' ' -f5- | rev |\
+sed 's/\[slave//g;' | tr '\t' '    ' )
+
+chosenDevice="$1"
+
+chosenID=$(echo "$IDlist" | grep "$chosenDevice" | awk '{print $NF}' | sed 's/id=//g')
+
+[ -z "$chosenID" ] && exit 1
+
+# disable the mouse acceleration (using xorg-xinput)
+xinput --set-prop "$chosenID" 'libinput Accel Speed' 0
+xinput --set-prop "$chosenID" 'libinput Accel Profile Enabled' 0, 1
+
+# set the mouse speed (using xorg-xset)
+xset mouse 1 0 &

+ 10 - 0
local-bin/st-exec

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# script to run st with a startup command
+
+[ -z "$1" ] && exit 1
+
+[ ! -d /tmp/norisa ] && mkdir -p /tmp/norisa
+echo "$1" > /tmp/norisa/st-exec-cmd
+
+st -e st-exec-sub

+ 7 - 0
local-bin/st-exec-sub

@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# just a subscript for st-exec
+
+[ ! -f /tmp/norisa/st-exec-cmd ] && exit 1
+
+zsh -c "$(cat /tmp/norisa/st-exec-cmd)"

+ 7 - 0
local-bin/stop-rec

@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# kills the running screencast
+
+kill "$(pgrep -f "screencast" | head -n 1)"
+kill "$(pgrep -f "screencast" | tail -n 1)"
+[ -z "$(pgrep -f "screencast")" ] && notify-send "screencasting" "stopped"

+ 14 - 0
local-bin/texclear

@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# script to clear the build files of a LaTeX/XeLaTeX build
+# I have vim run this file whenever I exit a .tex file.
+
+case "$1" in
+	*.tex)
+	file=$(readlink -f "$1")
+	dir=$(dirname "$file")
+	base="${file%.*}"
+	find "$dir"  -maxdepth 1 -type f -regextype gnu-awk -regex "^$base\\.(4tc|xref|tmp|pyc|pyo|fls|vrb|fdb_latexmk|bak|swp|aux|log|synctex\\(busy\\)|lof|lot|maf|idx|mtc|mtc0|nav|out|snm|toc|bcf|run\\.xml|synctex\\.gz|blg|bbl)" -delete ;;
+	*) printf "Give .tex file as argument.\\n" ;;
+esac
+

+ 9 - 0
local-bin/toggle-picom

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# script to toggle picom
+
+pgrep "picom" && killall picom && 
+notify-send "picom disabled" && exit
+
+picom &
+pgrep "picom" && notify-send "picom enabled"

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác