[
  {
    "path": ".gitignore",
    "content": "# Created by https://www.toptal.com/developers/gitignore/api/vim\n# Edit at https://www.toptal.com/developers/gitignore?templates=vim\n\n### Vim ###\n# Swap\n[._]*.s[a-v][a-z]\n[._]*.sw[a-p]\n[._]s[a-rt-v][a-z]\n[._]ss[a-gi-z]\n[._]sw[a-p]\n\n# Session\nSession.vim\n\n# Temporary\n.netrwhist\n*~\n# Auto-generated tag files\ntags\n# Persistent undo\n[._]*.un~\n\n# End of https://www.toptal.com/developers/gitignore/api/vim\n\n# mdBook build output\nbook/output/\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Attribution-NonCommercial-ShareAlike 4.0 International\n\n=======================================================================\n\nCreative Commons Corporation (\"Creative Commons\") is not a law firm and\ndoes not provide legal services or legal advice. Distribution of\nCreative Commons public licenses does not create a lawyer-client or\nother relationship. Creative Commons makes its licenses and related\ninformation available on an \"as-is\" basis. Creative Commons gives no\nwarranties regarding its licenses, any material licensed under their\nterms and conditions, or any related information. Creative Commons\ndisclaims all liability for damages resulting from their use to the\nfullest extent possible.\n\nUsing Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and\nconditions that creators and other rights holders may use to share\noriginal works of authorship and other material subject to copyright\nand certain other rights specified in the public license below. The\nfollowing considerations are for informational purposes only, are not\nexhaustive, and do not form part of our licenses.\n\n     Considerations for licensors: Our public licenses are\n     intended for use by those authorized to give the public\n     permission to use material in ways otherwise restricted by\n     copyright and certain other rights. Our licenses are\n     irrevocable. Licensors should read and understand the terms\n     and conditions of the license they choose before applying it.\n     Licensors should also secure all rights necessary before\n     applying our licenses so that the public can reuse the\n     material as expected. Licensors should clearly mark any\n     material not subject to the license. This includes other CC-\n     licensed material, or material used under an exception or\n     limitation to copyright. More considerations for licensors:\n    wiki.creativecommons.org/Considerations_for_licensors\n\n     Considerations for the public: By using one of our public\n     licenses, a licensor grants the public permission to use the\n     licensed material under specified terms and conditions. If\n     the licensor's permission is not necessary for any reason--for\n     example, because of any applicable exception or limitation to\n     copyright--then that use is not regulated by the license. Our\n     licenses grant only permissions under copyright and certain\n     other rights that a licensor has authority to grant. Use of\n     the licensed material may still be restricted for other\n     reasons, including because others have copyright or other\n     rights in the material. A licensor may make special requests,\n     such as asking that all changes be marked or described.\n     Although not required by our licenses, you are encouraged to\n     respect those requests where reasonable. More considerations\n     for the public:\n    wiki.creativecommons.org/Considerations_for_licensees\n\n=======================================================================\n\nCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International\nPublic License\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution-NonCommercial-ShareAlike 4.0 International Public License\n(\"Public License\"). To the extent this Public License may be\ninterpreted as a contract, You are granted the Licensed Rights in\nconsideration of Your acceptance of these terms and conditions, and the\nLicensor grants You such rights in consideration of benefits the\nLicensor receives from making the Licensed Material available under\nthese terms and conditions.\n\n\nSection 1 -- Definitions.\n\n  a. Adapted Material means material subject to Copyright and Similar\n     Rights that is derived from or based upon the Licensed Material\n     and in which the Licensed Material is translated, altered,\n     arranged, transformed, or otherwise modified in a manner requiring\n     permission under the Copyright and Similar Rights held by the\n     Licensor. For purposes of this Public License, where the Licensed\n     Material is a musical work, performance, or sound recording,\n     Adapted Material is always produced where the Licensed Material is\n     synched in timed relation with a moving image.\n\n  b. Adapter's License means the license You apply to Your Copyright\n     and Similar Rights in Your contributions to Adapted Material in\n     accordance with the terms and conditions of this Public License.\n\n  c. BY-NC-SA Compatible License means a license listed at\n     creativecommons.org/compatiblelicenses, approved by Creative\n     Commons as essentially the equivalent of this Public License.\n\n  d. Copyright and Similar Rights means copyright and/or similar rights\n     closely related to copyright including, without limitation,\n     performance, broadcast, sound recording, and Sui Generis Database\n     Rights, without regard to how the rights are labeled or\n     categorized. For purposes of this Public License, the rights\n     specified in Section 2(b)(1)-(2) are not Copyright and Similar\n     Rights.\n\n  e. Effective Technological Measures means those measures that, in the\n     absence of proper authority, may not be circumvented under laws\n     fulfilling obligations under Article 11 of the WIPO Copyright\n     Treaty adopted on December 20, 1996, and/or similar international\n     agreements.\n\n  f. Exceptions and Limitations means fair use, fair dealing, and/or\n     any other exception or limitation to Copyright and Similar Rights\n     that applies to Your use of the Licensed Material.\n\n  g. License Elements means the license attributes listed in the name\n     of a Creative Commons Public License. The License Elements of this\n     Public License are Attribution, NonCommercial, and ShareAlike.\n\n  h. Licensed Material means the artistic or literary work, database,\n     or other material to which the Licensor applied this Public\n     License.\n\n  i. Licensed Rights means the rights granted to You subject to the\n     terms and conditions of this Public License, which are limited to\n     all Copyright and Similar Rights that apply to Your use of the\n     Licensed Material and that the Licensor has authority to license.\n\n  j. Licensor means the individual(s) or entity(ies) granting rights\n     under this Public License.\n\n  k. NonCommercial means not primarily intended for or directed towards\n     commercial advantage or monetary compensation. For purposes of\n     this Public License, the exchange of the Licensed Material for\n     other material subject to Copyright and Similar Rights by digital\n     file-sharing or similar means is NonCommercial provided there is\n     no payment of monetary compensation in connection with the\n     exchange.\n\n  l. Share means to provide material to the public by any means or\n     process that requires permission under the Licensed Rights, such\n     as reproduction, public display, public performance, distribution,\n     dissemination, communication, or importation, and to make material\n     available to the public including in ways that members of the\n     public may access the material from a place and at a time\n     individually chosen by them.\n\n  m. Sui Generis Database Rights means rights other than copyright\n     resulting from Directive 96/9/EC of the European Parliament and of\n     the Council of 11 March 1996 on the legal protection of databases,\n     as amended and/or succeeded, as well as other essentially\n     equivalent rights anywhere in the world.\n\n  n. You means the individual or entity exercising the Licensed Rights\n     under this Public License. Your has a corresponding meaning.\n\n\nSection 2 -- Scope.\n\n  a. License grant.\n\n       1. Subject to the terms and conditions of this Public License,\n          the Licensor hereby grants You a worldwide, royalty-free,\n          non-sublicensable, non-exclusive, irrevocable license to\n          exercise the Licensed Rights in the Licensed Material to:\n\n            a. reproduce and Share the Licensed Material, in whole or\n               in part, for NonCommercial purposes only; and\n\n            b. produce, reproduce, and Share Adapted Material for\n               NonCommercial purposes only.\n\n       2. Exceptions and Limitations. For the avoidance of doubt, where\n          Exceptions and Limitations apply to Your use, this Public\n          License does not apply, and You do not need to comply with\n          its terms and conditions.\n\n       3. Term. The term of this Public License is specified in Section\n          6(a).\n\n       4. Media and formats; technical modifications allowed. The\n          Licensor authorizes You to exercise the Licensed Rights in\n          all media and formats whether now known or hereafter created,\n          and to make technical modifications necessary to do so. The\n          Licensor waives and/or agrees not to assert any right or\n          authority to forbid You from making technical modifications\n          necessary to exercise the Licensed Rights, including\n          technical modifications necessary to circumvent Effective\n          Technological Measures. For purposes of this Public License,\n          simply making modifications authorized by this Section 2(a)\n          (4) never produces Adapted Material.\n\n       5. Downstream recipients.\n\n            a. Offer from the Licensor -- Licensed Material. Every\n               recipient of the Licensed Material automatically\n               receives an offer from the Licensor to exercise the\n               Licensed Rights under the terms and conditions of this\n               Public License.\n\n            b. Additional offer from the Licensor -- Adapted Material.\n               Every recipient of Adapted Material from You\n               automatically receives an offer from the Licensor to\n               exercise the Licensed Rights in the Adapted Material\n               under the conditions of the Adapter's License You apply.\n\n            c. No downstream restrictions. You may not offer or impose\n               any additional or different terms or conditions on, or\n               apply any Effective Technological Measures to, the\n               Licensed Material if doing so restricts exercise of the\n               Licensed Rights by any recipient of the Licensed\n               Material.\n\n       6. No endorsement. Nothing in this Public License constitutes or\n          may be construed as permission to assert or imply that You\n          are, or that Your use of the Licensed Material is, connected\n          with, or sponsored, endorsed, or granted official status by,\n          the Licensor or others designated to receive attribution as\n          provided in Section 3(a)(1)(A)(i).\n\n  b. Other rights.\n\n       1. Moral rights, such as the right of integrity, are not\n          licensed under this Public License, nor are publicity,\n          privacy, and/or other similar personality rights; however, to\n          the extent possible, the Licensor waives and/or agrees not to\n          assert any such rights held by the Licensor to the limited\n          extent necessary to allow You to exercise the Licensed\n          Rights, but not otherwise.\n\n       2. Patent and trademark rights are not licensed under this\n          Public License.\n\n       3. To the extent possible, the Licensor waives any right to\n          collect royalties from You for the exercise of the Licensed\n          Rights, whether directly or through a collecting society\n          under any voluntary or waivable statutory or compulsory\n          licensing scheme. In all other cases the Licensor expressly\n          reserves any right to collect such royalties, including when\n          the Licensed Material is used other than for NonCommercial\n          purposes.\n\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\n  a. Attribution.\n\n       1. If You Share the Licensed Material (including in modified\n          form), You must:\n\n            a. retain the following if it is supplied by the Licensor\n               with the Licensed Material:\n\n                 i. identification of the creator(s) of the Licensed\n                    Material and any others designated to receive\n                    attribution, in any reasonable manner requested by\n                    the Licensor (including by pseudonym if\n                    designated);\n\n                ii. a copyright notice;\n\n               iii. a notice that refers to this Public License;\n\n                iv. a notice that refers to the disclaimer of\n                    warranties;\n\n                 v. a URI or hyperlink to the Licensed Material to the\n                    extent reasonably practicable;\n\n            b. indicate if You modified the Licensed Material and\n               retain an indication of any previous modifications; and\n\n            c. indicate the Licensed Material is licensed under this\n               Public License, and include the text of, or the URI or\n               hyperlink to, this Public License.\n\n       2. You may satisfy the conditions in Section 3(a)(1) in any\n          reasonable manner based on the medium, means, and context in\n          which You Share the Licensed Material. For example, it may be\n          reasonable to satisfy the conditions by providing a URI or\n          hyperlink to a resource that includes the required\n          information.\n       3. If requested by the Licensor, You must remove any of the\n          information required by Section 3(a)(1)(A) to the extent\n          reasonably practicable.\n\n  b. ShareAlike.\n\n     In addition to the conditions in Section 3(a), if You Share\n     Adapted Material You produce, the following conditions also apply.\n\n       1. The Adapter's License You apply must be a Creative Commons\n          license with the same License Elements, this version or\n          later, or a BY-NC-SA Compatible License.\n\n       2. You must include the text of, or the URI or hyperlink to, the\n          Adapter's License You apply. You may satisfy this condition\n          in any reasonable manner based on the medium, means, and\n          context in which You Share Adapted Material.\n\n       3. You may not offer or impose any additional or different terms\n          or conditions on, or apply any Effective Technological\n          Measures to, Adapted Material that restrict exercise of the\n          rights granted under the Adapter's License You apply.\n\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\n  a. for the avoidance of doubt, Section 2(a)(1) grants You the right\n     to extract, reuse, reproduce, and Share all or a substantial\n     portion of the contents of the database for NonCommercial purposes\n     only;\n\n  b. if You include all or a substantial portion of the database\n     contents in a database in which You have Sui Generis Database\n     Rights, then the database in which You have Sui Generis Database\n     Rights (but not its individual contents) is Adapted Material,\n     including for purposes of Section 3(b); and\n\n  c. You must comply with the conditions in Section 3(a) if You Share\n     all or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\n  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\n     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\n     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\n     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\n     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\n     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\n     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\n     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\n     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\n     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\n  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\n     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\n     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\n     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\n     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\n     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\n     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\n     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\n     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\n  c. The disclaimer of warranties and limitation of liability provided\n     above shall be interpreted in a manner that, to the extent\n     possible, most closely approximates an absolute disclaimer and\n     waiver of all liability.\n\n\nSection 6 -- Term and Termination.\n\n  a. This Public License applies for the term of the Copyright and\n     Similar Rights licensed here. However, if You fail to comply with\n     this Public License, then Your rights under this Public License\n     terminate automatically.\n\n  b. Where Your right to use the Licensed Material has terminated under\n     Section 6(a), it reinstates:\n\n       1. automatically as of the date the violation is cured, provided\n          it is cured within 30 days of Your discovery of the\n          violation; or\n\n       2. upon express reinstatement by the Licensor.\n\n     For the avoidance of doubt, this Section 6(b) does not affect any\n     right the Licensor may have to seek remedies for Your violations\n     of this Public License.\n\n  c. For the avoidance of doubt, the Licensor may also offer the\n     Licensed Material under separate terms or conditions or stop\n     distributing the Licensed Material at any time; however, doing so\n     will not terminate this Public License.\n\n  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public\n     License.\n\n\nSection 7 -- Other Terms and Conditions.\n\n  a. The Licensor shall not be bound by any additional or different\n     terms or conditions communicated by You unless expressly agreed.\n\n  b. Any arrangements, understandings, or agreements regarding the\n     Licensed Material not stated herein are separate from and\n     independent of the terms and conditions of this Public License.\n\n\nSection 8 -- Interpretation.\n\n  a. For the avoidance of doubt, this Public License does not, and\n     shall not be interpreted to, reduce, limit, restrict, or impose\n     conditions on any use of the Licensed Material that could lawfully\n     be made without permission under this Public License.\n\n  b. To the extent possible, if any provision of this Public License is\n     deemed unenforceable, it shall be automatically reformed to the\n     minimum extent necessary to make it enforceable. If the provision\n     cannot be reformed, it shall be severed from this Public License\n     without affecting the enforceability of the remaining terms and\n     conditions.\n\n  c. No term or condition of this Public License will be waived and no\n     failure to comply consented to unless expressly agreed to by the\n     Licensor.\n\n  d. Nothing in this Public License constitutes or may be interpreted\n     as a limitation upon, or waiver of, any privileges and immunities\n     that apply to the Licensor or You, including from the legal\n     processes of any jurisdiction or authority.\n\n=======================================================================\n\nCreative Commons is not a party to its public\nlicenses. Notwithstanding, Creative Commons may elect to apply one of\nits public licenses to material it publishes and in those instances\nwill be considered the “Licensor.” The text of the Creative Commons\npublic licenses is dedicated to the public domain under the CC0 Public\nDomain Dedication. Except for the limited purpose of indicating that\nmaterial is shared under a Creative Commons public license or as\notherwise permitted by the Creative Commons policies published at\ncreativecommons.org/policies, Creative Commons does not authorize the\nuse of the trademark \"Creative Commons\" or any other trademark or logo\nof Creative Commons without its prior written consent including,\nwithout limitation, in connection with any unauthorized modifications\nto any of its public licenses or any other arrangements,\nunderstandings, or agreements concerning use of licensed material. For\nthe avoidance of doubt, this paragraph does not form part of the\npublic licenses.\n\nCreative Commons may be contacted at creativecommons.org.\n\n"
  },
  {
    "path": "README.md",
    "content": "# Learn Vim (the Smart Way)\n\n## What's This?\n\n*Learn Vim (the Smart Way)* is a guide to learn the good parts of Vim.\n\nThere are many places to learn Vim: the `vimtutor` is a great place to start and the `help` manual has all the references you will ever need. However, the average user needs something more than `vimtutor` and less than the `help` manual. This guide attempts to bridge that gap by highlighting only the key features to learn the most useful parts of Vim in the least amount of time possible.\n\nThis guide is written for both beginner and advanced Vimmers. It starts out with broad and simple concepts and ends with specific and advanced concepts. If you're an advanced user already, I encourage you to read this guide from start to finish anyway, because you may learn something new!\n\n## Read Locally (with Docker)\n\nYou can read this book locally with Docker. Just run:\n\n```bash\ndocker compose -f book/docker-compose.yml up --build\n```\n\nThen open [http://localhost:8080](http://localhost:8080).\n\n## I Want More Vim Tips!\n\nFollow [@learnvim](https://twitter.com/learnvim) for updates, Vim tips, etc.\n\n## Support This Project\n\nThis guide is and will always be free.\n\nIf you want to financially support this project, you can either [purchase this guide on Leanpub](https://leanpub.com/learnvim) or [buy me a coffee](https://www.buymeacoffee.com/iggredible)!\n\n<a href=\"https://leanpub.com/learnvim\"><img src=\"images/learn-vim-cover.png\" width=\"100\"></a>\n\n<a href=\"https://www.buymeacoffee.com/iggredible\" target=\"_blank\"><img src=\"https://cdn.buymeacoffee.com/buttons/v2/default-green.png\" alt=\"Buy Me A Coffee\" style=\"height: 60px !important;width: 217px !important;\" ></a>\n\n\n## Table Of Contents\n\n### Prologue\n\n- [Ch 0     - Read This First](./ch00_read_this_first.md)\n\n### Part 1: Learn Vim the Smart Way\n\n- [Ch 1     - Starting Vim](./ch01_starting_vim.md)\n- [Ch 2     - Buffers, Windows, and Tabs](./ch02_buffers_windows_tabs.md)\n- [Ch 3     - Opening and Searching Files](./ch03_searching_files.md)\n- [Ch 4     - Vim Grammar](./ch04_vim_grammar.md)\n- [Ch 5     - Moving in a File](./ch05_moving_in_file.md)\n- [Ch 6     - Insert Mode](./ch06_insert_mode.md)\n- [Ch 7     - The Dot command](./ch07_the_dot_command.md)\n- [Ch 8     - Registers](./ch08_registers.md)\n- [Ch 9     - Macros](./ch09_macros.md)\n- [Ch 10    - Undo](./ch10_undo.md)\n- [Ch 11    - Visual Mode](./ch11_visual_mode.md)\n- [Ch 12    - Search and Substitute](./ch12_search_and_substitute.md)\n- [Ch 13    - The Global Command](./ch13_the_global_command.md)\n- [Ch 14    - External Commands](./ch14_external_commands.md)\n- [Ch 15    - Command-line Mode](./ch15_command-line_mode.md)\n- [Ch 16    - Tags](./ch16_tags.md)\n- [Ch 17    - Fold](./ch17_fold.md)\n- [Ch 18    - Git](./ch18_git.md)\n- [Ch 19    - Compile](./ch19_compile.md)\n- [Ch 20    - Views, Sessions, and Viminfo](./ch20_views_sessions_viminfo.md)\n- [Ch 21    - Multiple File Operations](./ch21_multiple_file_operations.md)\n\n### Part 2: Customize Vim the Smart Way\n\n- [Ch 22 - Vimrc](./ch22_vimrc.md)\n- [Ch 23 - Vim Packages](./ch23_vim_packages.md)\n- [Ch 24 - Vim Runtime](./ch24_vim_runtime.md)\n\n### Part 3: Learn Vimscript the Smart Way\n\n- [Ch 25 - Vimscript Basic Data Types](./ch25_vimscript_basic_data_types.md)\n- [Ch 26 - Vimscript Conditionals And Loops](./ch26_vimscript_conditionals_and_loops.md)\n- [Ch 27 - Vimscript Variable Scopes](./ch27_vimscript_variable_scopes.md)\n- [Ch 28 - Vimscript Functions](./ch28_vimscript_functions.md)\n- [Ch 29 - Plugin Example: Writing a Titlecase Plugin](./ch29_plugin_example_writing-a-titlecase-plugin.md)\n\n## Translations\n- [Learn-Vim 中文翻译](https://wsdjeg.net/wiki/learn-vim/)(`zh-CN`)\n- [Learn-Vim Spanish](https://github.com/victorhck/learn-Vim-es)(`es`)\n\n## License & Copyright\nThe materials here are all © 2020-2021 Igor Irianto.\n\n<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\"><img alt=\"Creative Commons License\" style=\"border-width:0\" src=\"https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png\" /></a><br />\n\nThis work is licensed under a <a rel=\"license\" href=\"http://creativecommons.org/licenses/by-nc-sa/4.0/\">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</a>.\n"
  },
  {
    "path": "book/Dockerfile",
    "content": "# Stage 1: Build the book\nFROM peaceiris/mdbook:latest AS builder\n\nWORKDIR /book\n\n# Copy mdBook config and table of contents\nCOPY book/book.toml .\nCOPY book/src/SUMMARY.md src/SUMMARY.md\n\n# Copy all chapter files into the mdBook src directory\nCOPY ch*.md src/\n\n# Build the book\nRUN mdbook build\n\n# Stage 2: Serve with nginx\nFROM nginx:alpine\n\nCOPY --from=builder /book/output /usr/share/nginx/html\n\nEXPOSE 80\n"
  },
  {
    "path": "book/book.toml",
    "content": "[book]\ntitle = \"Learn Vim (the Smart Way)\"\nauthors = [\"Igor Irianto\"]\nlanguage = \"en\"\nsrc = \"src\"\n\n[build]\nbuild-dir = \"output\"\n\n[output.html]\ndefault-theme = \"light\"\npreferred-dark-theme = \"ayu\"\ngit-repository-url = \"https://github.com/iggredible/learn-vim\"\n"
  },
  {
    "path": "book/docker-compose.yml",
    "content": "services:\n  book:\n    build:\n      context: ..\n      dockerfile: book/Dockerfile\n    ports:\n      - \"8080:80\"\n"
  },
  {
    "path": "book/src/SUMMARY.md",
    "content": "# Summary\n\n# Prologue\n\n- [Read This First](./ch00_read_this_first.md)\n\n# Part 1: Learn Vim the Smart Way\n\n- [Starting Vim](./ch01_starting_vim.md)\n- [Buffers, Windows, and Tabs](./ch02_buffers_windows_tabs.md)\n- [Opening and Searching Files](./ch03_searching_files.md)\n- [Vim Grammar](./ch04_vim_grammar.md)\n- [Moving in a File](./ch05_moving_in_file.md)\n- [Insert Mode](./ch06_insert_mode.md)\n- [The Dot Command](./ch07_the_dot_command.md)\n- [Registers](./ch08_registers.md)\n- [Macros](./ch09_macros.md)\n- [Undo](./ch10_undo.md)\n- [Visual Mode](./ch11_visual_mode.md)\n- [Search and Substitute](./ch12_search_and_substitute.md)\n- [The Global Command](./ch13_the_global_command.md)\n- [External Commands](./ch14_external_commands.md)\n- [Command-line Mode](./ch15_command-line_mode.md)\n- [Tags](./ch16_tags.md)\n- [Fold](./ch17_fold.md)\n- [Git](./ch18_git.md)\n- [Compile](./ch19_compile.md)\n- [Views, Sessions, and Viminfo](./ch20_views_sessions_viminfo.md)\n- [Multiple File Operations](./ch21_multiple_file_operations.md)\n\n# Part 2: Customize Vim the Smart Way\n\n- [Vimrc](./ch22_vimrc.md)\n- [Vim Packages](./ch23_vim_packages.md)\n- [Vim Runtime](./ch24_vim_runtime.md)\n\n# Part 3: Learn Vimscript the Smart Way\n\n- [Vimscript Basic Data Types](./ch25_vimscript_basic_data_types.md)\n- [Vimscript Conditionals And Loops](./ch26_vimscript_conditionals_and_loops.md)\n- [Vimscript Variable Scopes](./ch27_vimscript_variable_scopes.md)\n- [Vimscript Functions](./ch28_vimscript_functions.md)\n- [Plugin Example: Writing a Titlecase Plugin](./ch29_plugin_example_writing-a-titlecase-plugin.md)\n"
  },
  {
    "path": "ch00_read_this_first.md",
    "content": "# Ch00. Read This First\n\n## Why This Guide Was Written\n\nThere are many places to learn Vim: the `vimtutor` is a great place to start and the `:help` manual has all the references you will ever need.\n\nHowever, the average user needs something more than `vimtutor` and less than the `:help` manual. This guide attempts to bridge that gap by highlighting only the key features to learn the most useful parts of Vim in the least amount of time possible.\n\nChances are you won't need all of Vim features. You probably only need to know about 20% of them to become a powerful Vimmer. This guide will show you which Vim features you will find most useful.\n\nThis is an opinionated guide. It covers techniques that I often use when using Vim. The chapters are sequenced based on which Vim topics I think would make the most logical sense for a beginner to learn.\n\nThis guide is example-heavy. When learning new concepts, examples are indispensable, and having numerous examples will solidify these concepts more effectively.\n\nSome of you may be wondering: 'Why do I need to learn Vimscript?' In my first year of using Vim, I was content with just knowing how to use Vim. Time passed and I started needing Vimscript more and more to write custom commands for my specific editing needs. As you are mastering Vim, you will find that, sooner or later, you will need to learn Vimscript. So why not sooner? Vimscript is a small language. You can learn its basics in just four chapters of this guide.\n\nYou can go far using Vim without knowing any Vimscript, but knowing it will help you excel even further.\n\nThis guide is written for both beginner and advanced Vimmers. It starts out with broad and simple concepts and ends with specific and advanced concepts. If you're an advanced user already, I encourage you to read this guide from start to finish anyway, because you may learn something new!\n\n## How to Transition to Vim From Using a Different Text Editor\n\nLearning Vim is a satisfying experience, albeit hard. There are two main approaches to learn Vim:\n\n1. Cold turkey\n2. Gradual\n\nGoing cold turkey means to stop using whatever editor / IDE you were using and to use Vim exclusively starting now. The downside of this method is you will have a serious productivity loss during the first week or two. If you're a full-time programmer, this method may not be feasible. That's why for most people, I believe the best way to transition to Vim is to use it gradually.\n\nTo gradually use Vim, during the first two weeks, spend an hour a day using Vim as your editor while the rest of the time you can use other editors. Many modern editors come with Vim plugins. When I first started, I used VSCode's popular Vim plugin for an hour per day. I gradually increased the time with the Vim plugin until I finally used it all day. Keep in mind that these plugins can only emulate a fraction of Vim features. To experience the full power of Vim like Vimscript, Command-line (Ex) Commands, and external commands integration, you will need to use Vim itself.\n\nThere were two pivotal moments that made me start to use Vim 100%: when I grasped that Vim has a grammar-like structure (see chapter 4) and the [fzf.vim](https://github.com/junegunn/fzf.vim) plugin (see chapter 3).\n\nThe first, when I realized Vim's grammar-like structure, was the defining moment that I finally understood what these Vim users were talking about. I didn't need to learn hundreds of unique commands. I only had to learn a small handful of commands and I could chain in a very intuitive way to do many things.\n\nThe second, the ability to quickly run a fuzzy file-search was the IDE feature that I used most. When I learned how to do that in Vim, I gained a major speed boost and never looked back ever since.\n\nEveryone programs differently. Upon introspection, you will find that there are one or two features from your favorite editor / IDE that you use all the time. Maybe it was fuzzy-search, jump-to-definition, or quick compilation. Whatever they may be, identify them quickly and learn how to implement those in Vim (chances are Vim can probably do them too). Your editing speed will receive a huge boost.\n\nOnce you can edit at 50% of the original speed, it's time to go full-time Vim.\n\n## How to Read This Guide\n\nThis is a practical guide. To become good in Vim you need to develop your muscle memory, not head knowledge.\n\nYou don't learn how to ride a bike by reading a guide about how to ride a bike. You need to actually ride a bike.\n\nYou need to type every command referred in this guide. Not only that, but you need to repeat them several times and try different combinations. Look up what other features the command you just learned has. The `:help` command and search engines are your best friends. Your goal is not to know everything about a command, but to be able to execute that command naturally and instinctively.\n\nAs much as I try to fashion this guide to be linear, some concepts in this guide have to be presented out-of-order. For example in chapter 1, I mention the substitute command (`:s`), even though it won't be covered until chapter 12. To remedy this, whenever a new concept that has not been covered yet is mentioned early, I will provide a quick how-to guide without a detailed explanation. So please bear with me :).\n\n## More Help\n\nHere's one extra tip to use the help manual: suppose you want to learn more about what `Ctrl-P` does in insert mode. If you merely search for `:h CTRL-P`, you will be directed to normal mode's `Ctrl-P`. This is not the `Ctrl-P` help that you're looking for. In this case, search instead for `:h i_CTRL-P`. The appended `i_` represents the insert mode. Pay attention to which mode it belongs to.\n\n## Syntax\n\nMost of the command or code-related phrases are in code-case (`like this`).\n\nStrings are surrounded by a pair of double-quotes (\"like this\").\n\nVim commands can be abbreviated. For example, `:join` can be abbreviated as `:j`. Throughout the guide, I will be mixing the shorthand and the longhand descriptions. For commands that are not frequently used in this guide, I will use the longhand version. For commands that are frequently used, I will use the shorthand version. I apologize for the inconsistencies. In general, whenever you spot a new command, always check it on `:help` to see its abbreviations.\n\n## Vimrc\n\nAt various points in the guide, I will refer to vimrc options. If you're new to Vim, a vimrc is like a config file.\n\nVimrc won't be covered until chapter 22. For the sake of clarity, I will show briefly here how to set it up.\n\nSuppose you need to set the number options (`set number`). If you don't have a vimrc already, create one. It is usually placed in your home directory and named `.vimrc`. Depending on your OS, the location may differ. In macOS, I have it on `~/.vimrc`. To see where you should put yours, check out `:h vimrc`.\n\nInside it, add `set number`. Save it (`:w`), then source it (`:source %`). You should now see line numbers displayed on the left side.\n\nAlternatively, if you don't want to make a permanent setting change, you can always run the `set` command inline, by running `:set number`. The downside of this approach is that this setting is temporary. When you close Vim, the option disappears.\n\nSince we are learning about Vim and not Vi, a setting that you must have is the `nocompatible` option. Add `set nocompatible` in your vimrc. Many Vim-specific features are disabled when it is running on `compatible` option.\n\nIn general, whenever a passage mentions a vimrc option, just add that option into vimrc, save it, and source it.\n\n## Future, Errors, Questions\n\nExpect more updates in the future. If you find any errors or have any questions, please feel free to reach out.\n\nI also have planned a few more upcoming chapters, so stay tuned!\n\n## I Want More Vim Tricks\n\nTo learn more about Vim, please follow [@learnvim](https://twitter.com/learnvim).\n\n## Thank Yous\n\nThis guide wouldn't be possible without Bram Molenaar for creating Vim, my wife who had been very patient and supportive throughout the journey, all the [contributors](https://github.com/iggredible/Learn-Vim/graphs/contributors) of the learn-vim project, the Vim community, and many, many others that weren't mentioned.\n\nThank you. You all help make text editing fun :)\n\n\n## Link\n- Next [Ch01. Starting Vim](./ch01_starting_vim.md)\n"
  },
  {
    "path": "ch01_starting_vim.md",
    "content": "# Ch01. Starting Vim\n\nIn this chapter, you will learn different ways to start Vim from the terminal. I was using Vim 8.2 when writing this guide. If you use Neovim or an older version of Vim, you should be mostly fine, but be aware that some commands might not be available.\n\n## Installing\n\nI won't go through the detailed instructions on how to install Vim on a specific machine. The good news is that most Unix-based computers should come with Vim installed already. If not, most distros should have some instructions on how to install Vim.\n\nTo download more information about the Vim installation process, check out the official download website or the official GitHub repository:\n- [Vim website](https://www.vim.org/download.php)\n- [Vim GitHub](https://github.com/vim/vim)\n\n## The Vim Command\n\nNow that you have Vim installed, run this from the terminal:\n\n```bash\nvim\n```\n\nYou should see an intro screen. This is where you will be working on your new file. Unlike most text editors and IDEs, Vim is a modal editor. If you want to type \"hello\", you need to switch to insert mode with `i`. Input `ihello<Esc>` to insert the text, \"hello\".\n\n## Exiting Vim\n\nThere are several ways to exit Vim. The most common one is to type:\n\n```\n:quit\n```\n\nYou can type `:q` for short. This command is a command for command-line mode (another one of Vim modes). If you type `:` in normal mode, the cursor will move to the bottom of the screen, where you can type some commands. You will learn about command-line mode later in chapter 15. If you are in insert mode, typing `:` will literally produce the character \":\" on the screen. In this case, you need to switch back to normal mode. Type `<Esc>` to switch to normal mode. By the way, you can also return to normal mode from command-line mode by pressing `<Esc>`. You will notice that you can \"escape\" out of several Vim modes back to normal mode by pressing `<Esc>`.\n\n## Saving a File\n\nTo save your changes, type:\n\n```\n:write\n```\n\nYou can also type `:w` for short. If this is a new file, you will need to give it a name before you can save it. Let's name it `file.txt`. Run:\n\n```\n:w file.txt\n```\n\nTo save and quit, you can combine the `:w` and `:q` commands:\n\n```\n:wq\n```\n\nTo quit without saving any changes, add `!` after `:q` to force quit:\n\n```\n:q!\n```\n\nThere are other ways to exit Vim, but these are the ones you will use on a daily basis.\n\n## Help\n\nThroughout this guide, I will refer you to various Vim help pages. You can go to the help page by typing `:help {some-command}` (`:h` for short). You can pass to the `:h` command a topic or a command name as an argument. For example, to learn about different ways to quit Vim, type:\n\n```\n:h write-quit\n```\n\nHow did I know to search for \"write-quit\"? I actually didn't. I just typed `:h`, then \"quit\", then `<Tab>`. Vim displayed relevant keywords to choose from. If you ever need to look up something (\"I wish Vim can do this...\"), just type `:h` and try inputting some keywords, then press `<Tab>`.\n\n## Opening a File\n\nTo open a file (`hello1.txt`) on Vim from the terminal, run:\n\n```bash\nvim hello1.txt\n```\n\nYou can also open multiple files at once:\n\n```bash\nvim hello1.txt hello2.txt hello3.txt\n```\n\nVim opens `hello1.txt`, `hello2.txt`, and `hello3.txt` in separate buffers. You will learn about buffers in the next chapter.\n\n## Arguments\n\nYou can pass different flags and options to the `vim` terminal command.\n\nTo check the current Vim version, run:\n\n```bash\nvim --version\n```\n\nThis tells you the current Vim version and all available features, which will be prefixed by either `+` or `-`. Some features in this guide require certain features to be available. For example, you will explore Vim's command-line history in a later chapter using the `:history` command. Your installation of Vim needs to have the `+cmdline_history` feature for the command to work. There is a good chance that your installation of Vim has all the necessary features, especially if it came from a popular download source.\n\nMany things you do from the terminal can also be done from inside Vim. To see the version from *inside* Vim, you can run this: \n\n```\n:version\n```\n\nIf you want to open the file `hello.txt` and immediately execute a Vim command, you can pass to the `vim` command the `+{cmd}` option.\n\nIn Vim, you can substitute strings with the `:s` command (short for `:substitute`). If you want to open `hello.txt` and substitute all instances of \"pancake\" with \"bagel\", run:\n\n```bash\nvim +%s/pancake/bagel/g hello.txt\n```\n\nThese Vim commands can be stacked:\n\n```bash\nvim +%s/pancake/bagel/g +%s/bagel/egg/g +%s/egg/donut/g hello.txt\n```\n\nVim will:\n1. Replace all instances of \"pancake\" with \"bagel\"\n2. Then it will replace \"bagel\" with \"egg\"\n3. Then it will replace \"egg\" with \"donut\"\nYou will learn substitution in a later chapter.\n\nYou can also pass the `-c` option followed by a Vim command, instead of using the `+` syntax:\n\n```bash\nvim -c %s/pancake/bagel/g hello.txt\nvim -c %s/pancake/bagel/g -c %s/bagel/egg/g -c %s/egg/donut/g hello.txt\n```\n\n## Opening Multiple Windows\n\nYou can launch Vim on split horizontal and vertical windows using the `-o` and `-O` options, respectively.\n\nTo open Vim with 2 horizontal windows, run:\n\n```bash\nvim -o2\n```\n\nTo open Vim with 5 horizontal windows, run:\n\n```bash\nvim -o5\n```\n\nTo open Vim with 5 horizontal windows and fill up the first two with `hello1.txt` and `hello2.txt`, run:\n\n```bash\nvim -o5 hello1.txt hello2.txt\n```\n\nTo open Vim with 2 vertical windows, 5 vertical windows, and 5 vertical windows with two files, `hello1.txt` and `hello2.txt`:\n\n```bash\nvim -O2\nvim -O5\nvim -O5 hello1.txt hello2.txt\n```\n\n## Suspending\n\nIf you need to suspend Vim while in the middle of editing, you can press `Ctrl-z`. You can also run either the `:stop` or `:suspend` command. To return to the suspended Vim, run `fg` from the terminal.\n\n## Starting Vim the Smart Way\n\nThe `vim` command can take many different options, just like any other terminal command. Two options allow you to pass a Vim command-line mode command as a parameter: `+{cmd}` and `-c cmd`. As you learn more commands throughout this guide, see if you can execute them when starting Vim. Also, being a terminal command, `vim` can be combined with many other terminal commands. For example, you can redirect the output of the `ls` command to be edited in Vim with `ls -l | vim -`.\n\nTo learn more about `vim` command in the terminal, check out `man vim`. To learn more about the Vim editor, continue reading this guide and use the `:help` command.\n\n## Link\n- Prev [Ch00. Read This First](./ch00_read_this_first.md)\n- Next [Ch02. Buffers, Windows, and Tabs](./ch02_buffers_windows_tabs.md)\n"
  },
  {
    "path": "ch02_buffers_windows_tabs.md",
    "content": "# Ch02. Buffers, Windows, and Tabs\n\nIf you've used a modern text editor before, you are probably familiar with windows and tabs. Vim uses three display abstractions instead of two:\n- buffers\n- windows\n- tabs.\nIn this chapter, I will explain what buffers, windows, and tabs are and how they work in Vim.\n\nBefore you start, make sure you have the `set hidden` option in your vimrc. Without it, you will be prompted to save your file whenever you try to switch out of any unsaved buffers (you don't want that if you want to move quickly). I haven't covered what a vimrc is yet. A vimrc file can usually be found in your home directory and is named `.vimrc` (i.e., the full path to this file `~/.vimrc`). I have my vimrc on `~/.vimrc`. To see where you should create your vimrc, check out `:h vimrc`. If you don't have a vimrc already, create one by running `vim +w ~/.vimrc` in your terminal. Inside it, add:\n\n```\nset hidden\n```\n\nSave it, then source it (run `:source %` from inside the vimrc).\n\n## Buffers\n\nWhat is a *buffer*?\n\nA buffer is an in-memory space where you can write and edit text. When you open a file in Vim, the data in that file is bound to a buffer. When you open 3 files in Vim, 3 buffers will be created for each of them.\n\nHave two empty files, `file1.js` and `file2.js` available (if possible, create them with Vim by running, say, `vim +wn file1.js +wq file2.js` in the terminal). Run this in the terminal:\n\n```bash\nvim file1.js\n```\n\nWhat you are seeing is the *buffer* for `file1.js`. Whenever you open a new file, Vim creates a new buffer.\n\nExit Vim. This time, open two new files:\n\n```bash\nvim file1.js file2.js\n```\n\nVim is currently displaying the `file1.js` buffer, but it actually creates two buffers: the `file1.js` buffer and the `file2.js` buffer. Run `:buffers` to see all the buffers (alternatively, you can use `:ls` or `:files` too). You should see *both* `file1.js` and `file2.js` listed. Running `vim file1 file2 file3 ... filen` creates `n` buffers. Each time you open a new file, Vim creates a new buffer for that file.\n\nThere are several ways you can traverse buffers:\n- `:bnext` to go to the next buffer (`:bprevious` to go to the previous buffer).\n- `:buffer` + filename. Vim can autocomplete any filename for you if you press `<Tab>`.\n- `:buffer` + `n`, where `n` is the buffer number. For example, typing `:buffer 2` will take you to buffer #2.\n- Jump to the older position in the jump list with `Ctrl-O` and to the newer position with `Ctrl-I`. These are not buffer-specific methods, but they can be used to jump between different buffers. I will explain jumps in further detail in chapter 5.\n- Go to the previously edited buffer with `Ctrl-^`.\n\nOnce Vim creates a buffer, it will remain in your buffer list. To remove the current buffer, you can type `:bdelete`. This command also accepts a buffer number as a parameter (e.g., `:bdelete 3` to delete buffer #3) or a filename (`:bdelete` then use `<Tab>` to autocomplete).\n\nFor me, the hardest part of learning about buffers was visualizing how they worked, because my mind was so used to the windows of a mainstream text editor I had been using. Buffers can be analogized to a deck of playing cards. If I have 2 buffers, I have a stack of 2 cards. The card on top is the only card I see, but I know there is another card below it. If I see `file1.js` buffer displayed then the `file1.js` card is on the top of the deck. I can't see the other card, `file2.js` here, but it's there. If I switch buffers to `file2.js`, that `file2.js` card is now on the top of the deck and `file1.js` card is below it.\n\nIf you haven't used Vim before, this is a new concept. Take your time to understand it.\n\n## Exiting Vim\n\nBy the way, if you have multiple buffers opened, you can close all of them with quit-all:\n\n```\n:qall\n```\n\nIf you want to close without saving your changes, just add `!` at the end:\n\n```\n:qall!\n```\n\nTo save and quit all, run:\n\n```\n:wqall\n```\n\n## Windows\n\nA window is a viewport on a buffer. If you're coming from a mainstream editor, this concept may be familiar to you. Most text editors have the ability to display multiple windows. In Vim, you can also have multiple windows.\n\nLet's open `file1.js` from the terminal again:\n\n```bash\nvim file1.js\n```\n\nEarlier I wrote that you're looking at the `file1.js` buffer. While that was correct, it was also incomplete. You are looking at the `file1.js` buffer, displayed through **a window**. A window is what you are viewing a buffer through.\n\nDon't quit Vim yet. Run:\n\n```\n:split file2.js\n```\n\nNow you are looking at two buffers through **two windows**. The top window displays the `file2.js` buffer. The bottom window displays the `file1.js` buffer.\n\nIf you want to navigate between windows, use these shortcuts:\n\n```\nCtrl-W h    Moves the cursor to the left window\nCtrl-W j    Moves the cursor to the lower window\nCtrl-W k    Moves the cursor to the upper window\nCtrl-W l    Moves the cursor to the right window\n```\n\nNow run:\n\n```\n:vsplit file3.js\n```\n\nYou are now seeing three windows displaying three buffers. One window displays the `file3.js` buffer, another window displays the `file2.js` buffer, and another window displays the `file1.js` buffer.\n\nYou can have multiple windows display the same buffer. While you're on the top left window, type:\n\n```\n:buffer file2.js\n```\n\nNow both of the top windows are displaying the `file2.js` buffer. If you start typing on either of the `file2.js` windows, both windows containing the `file2.js` buffer will be updated in real-time.\n\nTo close the current window, you can run `Ctrl-W C` or type `:quit`. When you close a window, the buffer will still be there (run `:buffers` to confirm this).\n\nHere are some useful normal-mode window commands:\n\n```\nCtrl-W V    Opens a new vertical split\nCtrl-W S    Opens a new horizontal split\nCtrl-W C    Closes a window\nCtrl-W O    Makes the current window the only one on screen and closes other windows\n```\n\nAnd here is a list of useful window command-line commands:\n\n```\n:vsplit filename    Split window vertically\n:split filename     Split window horizontally\n:new filename       Create new window\n```\n\nTake your time to understand them. For more information, check out `:h window`.\n\n## Tabs\n\nA tab is a collection of windows. Think of it like a layout for windows. In most modern text editors (and modern internet browsers), a tab means an open file / page; when you close it, that file / page goes away. In Vim, a tab does not represent an opened file. When you close a tab in Vim, you are not closing a file; you are only closing the layout. The files opened in that layout are still not closed; they are still open in their buffers.\n\nLet's see Vim tabs in action. Open `file1.js`:\n\n```bash\nvim file1.js\n```\n\nTo open `file2.js` in a new tab:\n\n```\n:tabnew file2.js\n```\n\nYou can also let Vim autocomplete the file you want to open in a *new tab* by pressing `<Tab>` (no pun intended).\n\nBelow is a list of useful tab navigations:\n\n```\n:tabnew file.txt    Open file.txt in a new tab\n:tabclose           Close the current tab\n:tabnext            Go to next tab\n:tabprevious        Go to previous tab\n:tablast            Go to last tab\n:tabfirst           Go to first tab\n```\n\nYou can also run `gt` to go to next tab page (you can go to previous tab with `gT`). You can pass count as argument to `gt`, where count is the tab number; for example, to go to the third tab, do `3gt`.\n\nOne advantage of having multiple tabs is you can have different window arrangements in different tabs. Maybe you want your first tab to have 3 vertical windows, and your second tab to have a layout consisting of horizontal and vertical windows mixed together. Tab is the perfect tool for this job!\n\nTo start Vim with multiple tabs, you can run this from the terminal:\n\n```bash\nvim -p file1.js file2.js file3.js\n```\n\n## Moving in 3D\n\nMoving between windows is like traveling two-dimensionally along the X-Y axis in a Cartesian coordinate system. You can move to the top, right, bottom, and left window with `Ctrl-W K/L/J/H`, respectively.\n\nMoving between buffers is like traveling across the Z axis in a Cartesian coordinate system. Imagine your buffer files lining up across the Z axis. You can traverse the Z axis one buffer at a time using `:bnext` and `:bprevious`. You can jump to any coordinate in the Z axis with `:buffer filename/buffernumber`.\n\nYou can move in *three-dimensional space* by combining window and buffer movements. You can move to the top, right, bottom, or left window (X-Y navigations) with window movements. Since each window contains a set of buffers, you can move forward and backward (Z navigations) with buffer movements.\n\n## Using Buffers, Windows, and Tabs the Smart Way\n\nYou have learned what buffers, windows, and tabs are and how they work in Vim. Now that you understand them better, you can use them in your own workflow.\n\nEveryone has a different workflow. Here is mine for example:\n- First, I use buffers to store all the required files for the current task. Vim can handle many opened buffers before it starts slowing down. Plus having many buffers open won't crowd my screen. I am only seeing one buffer (assuming I only have one window) at any time, allowing me to focus on one screen. When I need to go somewhere, I can quickly fly to any open buffer anytime.\n- I use multiple windows to view multiple buffers at once, usually when diffing files, reading docs, or following a code flow. I try to keep the number of windows opened to no more than three, because my screen will get crowded (I use a small laptop). When I am done, I close any extra windows. Fewer windows means fewer distractions.\n- Instead of tabs, I use [tmux](https://github.com/tmux/tmux/wiki) windows. I usually use multiple tmux windows at once. For example, one tmux window for client-side code and another for backend code.\n\nMy workflow may look different from yours based on your editing style, and that's fine. Experiment to discover your own flow and what suits your coding style.\n\n## Link\n- Prev [Ch01. Starting Vim](./ch01_starting_vim.md)\n- Next [Ch03. Searching Files](./ch03_searching_files.md)\n"
  },
  {
    "path": "ch03_searching_files.md",
    "content": "# Ch03. Searching Files\n\nThe goal of this chapter is to give you an introduction on how to search quickly in Vim. Being able to search quickly is a great way to jump-start your Vim productivity. When I figured out how to search files quickly, I made the switch to use Vim full-time.\n\nThis chapter is divided into two parts: how to search without plugins and how to search with [fzf.vim](https://github.com/junegunn/fzf.vim) plugin. Let's get started!\n\n## Opening and Editing Files\n\nTo open a file in Vim, you can use `:edit`.\n\n```\n:edit file.txt\n```\n\nIf `file.txt` exists, it opens the `file.txt` buffer. If `file.txt` doesn't exist, it creates a new buffer for `file.txt`.\n\nAutocomplete with `<Tab>` works with `:edit`. For example, if your file is inside a [Rails](https://rubyonrails.org/) *a*pp *c*ontroller *u*sers controller directory `./app/controllers/users_controllers.rb`, you can use `<Tab>` to expand the terms quickly:\n\n```\n:edit a<Tab>c<Tab>u<Tab>\n```\n\n`:edit` accepts wildcards arguments. `*` matches any file in the current directory. If you are only looking for files with `.yml` extension in the current directory:\n\n```\n:edit *.yml<Tab>\n```\n\nVim will give you a list of all `.yml` files in the current directory to choose from.\n\nYou can use `**` to search recursively. If you want to look for all `*.md` files in your project, but you are not sure in which directories, you can do this:\n\n```\n:edit **/*.md<Tab>\n```\n\n`:edit` can be used to run `netrw`, Vim's built-in file explorer. To do that, give `:edit` a directory argument instead of file:\n\n```\n:edit .\n:edit test/unit/\n```\n\n## Searching Files With Find\n\nYou can find files with `:find`. For example:\n\n```\n:find package.json\n:find app/controllers/users_controller.rb\n```\n\nAutocomplete also works with `:find`:\n\n```\n:find p<Tab>                \" to find package.json\n:find a<Tab>c<Tab>u<Tab>    \" to find app/controllers/users_controller.rb\n```\n\nYou may notice that `:find` looks like `:edit`. What's the difference?\n\n## Find and Path\n\nThe difference is that `:find` finds file in `path`, `:edit` doesn't. Let's learn a little bit about `path`. Once you learn how to modify your paths, `:find` can become a powerful searching tool. To check what your paths are, do:\n\n```\n:set path?\n```\n\nBy default, yours probably look like this:\n\n```\npath=.,/usr/include,,\n```\n\n- `.` means to search in the directory of the currently opened file.\n- `,` means to search in the current directory.\n- `/usr/include` is the typical directory for C libraries header files.\n\nThe first two are important in our context and the third one can be ignored for now. The takeaway here is that you can modify your own paths, where Vim will look for files. Let's assume this is your project structure:\n\n```\napp/\n  assets/\n  controllers/\n    application_controller.rb\n    comments_controller.rb\n    users_controller.rb\n    ...\n```\n\nIf you want to go to `users_controller.rb` from the root directory, you have to go through several directories (and pressing a considerable amount of tabs). Often when working with a framework, you spend 90% of your time in a particular directory. In this situation, you only care about going to the `controllers/` directory with the least amount of keystrokes. The `path` setting can shorten that journey.\n\nYou need to add the `app/controllers/` to the current `path`. Here is how you can do it:\n\n```\n:set path+=app/controllers/\n```\n\nNow that your path is updated, when you type `:find u<Tab>`, Vim will now search inside `app/controllers/` directory for files starting with \"u\".\n\nIf you have a nested `controllers/` directory, like `app/controllers/account/users_controller.rb`, Vim won't find `users_controllers`. Instead, you need to add  `:set path+=app/controllers/**`  in order for autocompletion to find `users_controller.rb`. This is great! Now you can find the users controller with 1 press of tab instead of 3.\n\nYou might be thinking to add the entire project directories so when you press `tab`, Vim will search everywhere for that file, like this:\n\n```\n:set path+=$PWD/**\n```\n\n`$PWD` is the current working directory. If you try to add your entire project to `path` hoping to make all files reachable upon a `tab` press, although this may work for a small project, doing this will slow down your search significantly if you have a large number of files in your project. I recommend adding only the `path` of your most visited files / directories.\n\nYou can add the `set path+={your-path-here}` in your vimrc. Updating `path` takes only a few seconds and doing so can save you a lot of time.\n\n## Searching in Files With Grep\n\nIf you need to find in files (find phrases in files), you can use grep. Vim has two ways of doing that:\n\n- Internal grep (`:vim`. Yes, it is spelled `:vim`. It is short for `:vimgrep`).\n- External grep (`:grep`).\n\nLet's go through internal grep first. `:vim` has the following syntax:\n\n```\n:vim /pattern/ file\n```\n\n- `/pattern/` is a regex pattern of your search term.\n- `file` is the file argument. You can pass multiple arguments. Vim will search for the pattern inside the file argument. Similar to `:find`, you can pass it `*` and `**` wildcards.\n\nFor example, to look for all occurrences of \"breakfast\" string inside all ruby files (`.rb`) inside `app/controllers/` directory:\n\n```\n:vim /breakfast/ app/controllers/**/*.rb\n```\n\nAfter running that, you will be redirected to the first result. Vim's `vim` search command uses `quickfix` operation. To see all search results, run `:copen`. This opens a `quickfix` window. Here are some useful quickfix commands to get you productive immediately:\n\n```\n:copen        Open the quickfix window\n:cclose       Close the quickfix window\n:cnext        Go to the next error\n:cprevious    Go to the previous error\n:colder       Go to the older error list\n:cnewer       Go to the newer error list\n```\n\nTo learn more about quickfix, check out `:h quickfix`.\n\nYou may notice that running internal grep (`:vim`) can get slow if you have a large number of matches. This is because Vim loads each matching file into memory, as if it were being edited. If Vim finds a large number of files matching your search, it will load them all and therefore consume a large amount of memory.\n\nLet's talk about external grep. By default, it uses `grep` terminal command. To search for \"lunch\" inside a ruby file inside `app/controllers/` directory, you can do this:\n\n```\n:grep -R \"lunch\" app/controllers/\n```\n\nNote that instead of using `/pattern/`, it follows the terminal grep syntax `\"pattern\"`. It also displays all matches using `quickfix`.\n\nVim defines the `grepprg` variable to determine which external program to run when running the `:grep` Vim command so that you don't have to close Vim and invoke the terminal `grep` command. Later, I will show you how to change the default program invoked when using the `:grep` Vim command.\n\n## Browsing Files With Netrw\n\n`netrw` is Vim's built-in file explorer. It is useful to see a project's hierarchy. To run `netrw`, you need these two settings in your `.vimrc`:\n\n```\nset nocp\nfiletype plugin on\n```\n\nSince `netrw` is a vast topic, I will only cover the basic usage, but it should be enough to get you started. You can start `netrw` when you launch Vim by passing it a directory as a parameter instead of a file. For example:\n\n```\nvim .\nvim src/client/\nvim app/controllers/\n```\n\nTo launch `netrw` from inside Vim, you can use the `:edit` command and pass it a directory parameter instead of a filename:\n\n```\n:edit .\n:edit src/client/\n:edit app/controllers/\n```\n\nThere are other ways to launch `netrw` window without passing a directory:\n\n```\n:Explore     Starts netrw on current file\n:Sexplore    No kidding. Starts netrw on split top half of the screen\n:Vexplore    Starts netrw on split left half of the screen\n```\n\nYou can navigate `netrw` with Vim motions (motions will be covered in depth in a later chapter). If you need to create, delete, or rename a file or directory, here is a list of useful `netrw` commands:\n\n```\n%    Create a new file\nd    Create a new directory\nR    Rename a file or directory\nD    Delete a file or directory\n```\n\n`:h netrw` is very comprehensive. Check it out if you have time.\n\nIf you find `netrw` too bland and need more flavor, [vim-vinegar](https://github.com/tpope/vim-vinegar) is a good plugin to improve `netrw`. If you're looking for a different file explorer, [NERDTree](https://github.com/preservim/nerdtree) is a good alternative. Check them out!\n\n## Fzf\n\nNow that you've learned how to search files in Vim with built-in tools, let's learn how to do it with plugins.\n\nOne thing that modern text editors get right and that Vim didn't is how easy it is to find files, especially via fuzzy search. In this second half of the chapter, I will show you how to use [fzf.vim](https://github.com/junegunn/fzf.vim) to make searching in Vim easy and powerful.\n\n## Setup\n\nFirst, make sure you have [fzf](https://github.com/junegunn/fzf) and [ripgrep](https://github.com/BurntSushi/ripgrep) downloaded. Follow the instructions on their GitHub repo. The commands `fzf` and `rg` should now be available after successful installs.\n\nRipgrep is a search tool much like grep (hence the name). It is generally faster than grep and has many useful features. Fzf is a general-purpose command-line fuzzy finder. You can use it with any commands, including ripgrep. Together, they make a powerful search tool combination.\n\nFzf does not use ripgrep by default, so we need to tell fzf to use ripgrep by defining a `FZF_DEFAULT_COMMAND` variable. In my `.zshrc` (`.bashrc` if you use bash), I have these:\n\n```\nif type rg &> /dev/null; then\n  export FZF_DEFAULT_COMMAND='rg --files'\n  export FZF_DEFAULT_OPTS='-m'\nfi\n```\n\nPay attention to `-m` in `FZF_DEFAULT_OPTS`. This option allows us to make multiple selections with `<Tab>` or `<Shift-Tab>`. You don't need this line to make fzf work with Vim, but I think it is a useful option to have. It will come in handy when you want to perform search and replace in multiple files which I'll cover in just a little. The fzf command accepts many more options, but I won't cover them here. To learn more, check out [fzf's repo](https://github.com/junegunn/fzf#usage) or `man fzf`. At minimum you should have `export FZF_DEFAULT_COMMAND='rg'`.\n\nAfter installing fzf and ripgrep, let's set up the fzf plugin. I am using [vim-plug](https://github.com/junegunn/vim-plug) plugin manager in this example, but you can use any plugin managers.\n\nAdd these inside your `.vimrc` plugins. You need to use [fzf.vim](https://github.com/junegunn/fzf.vim) plugin (created by the same fzf author).\n\n```\ncall plug#begin()\nPlug 'junegunn/fzf.vim'\nPlug 'junegunn/fzf', { 'do': { -> fzf#install() } }\ncall plug#end()\n```\n\nAfter adding these lines, you will need to open `vim` and run `:PlugInstall`. It will install all plugins that are defined in your `vimrc` file and are not installed. In our case, it will install `fzf.vim` and `fzf`. \n\nFor more info about this plugin, you can check out [fzf.vim repo](https://github.com/junegunn/fzf/blob/master/README-VIM.md).\n\n## Fzf Syntax\n\nTo use fzf efficiently, you should learn some basic fzf syntax. Fortunately, the list is short:\n\n- `^` is a prefix exact match. To search for a phrase starting with \"welcome\": `^welcome`.\n- `$` is a suffix exact match. To search for a phrase ending with \"my friends\": `friends$`.\n- `'` is an exact match. To search for the phrase \"welcome my friends\": `'welcome my friends`.\n- `|` is an \"or\" match. To search for either \"friends\" or \"foes\": `friends | foes`.\n- `!` is an inverse match. To search for phrase containing \"welcome\" and not \"friends\": `welcome !friends`\n\nYou can mix and match these options. For example, `^hello | ^welcome friends$` will search for the phrase starting with either \"welcome\" or \"hello\" and ending with \"friends\".\n\n## Finding Files\n\nTo search for files inside Vim using fzf.vim plugin, you can use the `:Files` method. Run `:Files` from Vim and you will be prompted with fzf search prompt.\n\nSince you will be using this command frequently, it is good to have this mapped to a keyboard shortcut. I map mine to `Ctrl-f`. In my vimrc, I have this:\n\n```\nnnoremap <silent> <C-f> :Files<CR>\n```\n\n## Finding in Files\n\nTo search inside files, you can use the `:Rg` command.\n\nAgain, since you will probably use this frequently, let's map it to a keyboard shortcut. I map mine to `<Leader>f`. The `<Leader>` key is mapped to `\\` by default.\n\n```\nnnoremap <silent> <Leader>f :Rg<CR>\n```\n\n## Other Searches\n\nFzf.vim provides many other search commands. I won't go through each one of them here, but you can check them out [here](https://github.com/junegunn/fzf.vim#commands).\n\nHere's what my fzf maps look like:\n\n```\nnnoremap <silent> <Leader>b :Buffers<CR>\nnnoremap <silent> <C-f> :Files<CR>\nnnoremap <silent> <Leader>f :Rg<CR>\nnnoremap <silent> <Leader>/ :BLines<CR>\nnnoremap <silent> <Leader>' :Marks<CR>\nnnoremap <silent> <Leader>g :Commits<CR>\nnnoremap <silent> <Leader>H :Helptags<CR>\nnnoremap <silent> <Leader>hh :History<CR>\nnnoremap <silent> <Leader>h: :History:<CR>\nnnoremap <silent> <Leader>h/ :History/<CR>\n```\n\n## Replacing Grep With Rg\n\nAs mentioned earlier, Vim has two ways to search in files: `:vim` and `:grep`. `:grep` uses external search tool that you can reassign using the `grepprg` keyword. I will show you how to configure Vim to use ripgrep instead of terminal grep when running the `:grep` command.\n\nNow let's setup `grepprg` so that the `:grep` Vim command uses ripgrep. Add this in your vimrc:\n\n```\nset grepprg=rg\\ --vimgrep\\ --smart-case\\ --follow\n```\n\nFeel free to modify some of the options above! For more information on what the options above mean, check out `man rg`.\n\nAfter you updated `grepprg`, now when you run `:grep`, it runs `rg --vimgrep --smart-case --follow` instead of `grep`.  If you want to search for \"donut\" using ripgrep, you can now run a more succinct command `:grep \"donut\"` instead of `:grep \"donut\" . -R` \n\nJust like the old `:grep`, this new `:grep` also uses quickfix to display results.\n\nYou might wonder, \"Well, this is nice but I never used `:grep` in Vim, plus can't I just use `:Rg` to find phrases in files? When will I ever need to use `:grep`?\n\nThat is a very good question. You may need to use `:grep` in Vim to do search and replace in multiple files, which I will cover next.\n\n## Search and Replace in Multiple Files\n\nModern text editors like VSCode make it very easy to search and replace a string across multiple files. In this section, I will show you two different methods to easily do that in Vim.\n\nThe first method is to replace *all* matching phrases in your project. You will need to use `:grep`. If you want to replace all instances of \"pizza\" with \"donut\", here's what you do:\n\n```\n:grep \"pizza\"\n:cfdo %s/pizza/donut/g | update\n```\n\nLet's break down the commands:\n\n1. `:grep pizza` uses ripgrep to search for all instances of \"pizza\" (by the way, this would still work even if you didn't reassign `grepprg` to use ripgrep. You would have to do `:grep \"pizza\" . -R` instead of `:grep \"pizza\"`).\n2. `:cfdo` executes any command you pass to all files in your quickfix list. In this case, your command is the substitution command `%s/pizza/donut/g`. The pipe (`|`) is a chain operator. The `update` command saves each file after substitution. I will cover the substitute command in more depth in a later chapter.\n\nThe second method is to search and replace in selected files. With this method, you can manually choose which files you want to perform select-and-replace on. Here is what you do:\n\n1. Clear your buffers first. It is imperative that your buffer list contains only the files you want to apply the replace on. You can either restart Vim or run `:%bd | e#` command (`%bd` deletes all the buffers and `e#` opens the file you were just on).\n2. Run `:Files`.\n3. Select all files you want to perform search-and-replace on. To select multiple files, use `<Tab>` / `<Shift-Tab>`. This is only possible if you have the multiple flag (`-m`) in `FZF_DEFAULT_OPTS`.\n4. Run `:bufdo %s/pizza/donut/g | update`. The command `:bufdo %s/pizza/donut/g | update` looks similar to the earlier `:cfdo %s/pizza/donut/g | update` command. The difference is instead of substituting all quickfix entries (`:cfdo`), you are substituting all buffer entries (`:bufdo`).\n\n## Learn Search the Smart Way\n\nSearching is the bread-and-butter of text editing. Learning how to search well in Vim will improve your text editing workflow significantly.\n\nFzf.vim is a game-changer. I can't imagine using Vim without it. I think it is very important to have a good search tool when starting Vim. I've seen people struggling to transition to Vim because it seems to be missing critical features modern text editors have, like an easy and powerful search feature. I hope this chapter will help you to make the transition to Vim easier. \n\nYou also just saw Vim's extensibility in action - the ability to extend search functionality with a plugin and an external program. In the future, keep in mind what other features you wish to extend Vim with. Chances are, it's already in Vim, someone has created a plugin or there is a program for it already. Next, you'll learn about a very important topic in Vim: Vim grammar.\n\n## Link\n- Prev [Ch02. Buffers, Windows, and Tabs](./ch02_buffers_windows_tabs.md)\n- Next [Ch04. Vim Grammar](./ch04_vim_grammar.md)\n"
  },
  {
    "path": "ch04_vim_grammar.md",
    "content": "# Ch04. Vim Grammar\n\nIt is easy to get intimidated by the complexity of Vim commands. If you see a Vim user doing `gUfV` or `1GdG`, you may not immediately know what these commands do. In this chapter, I will break down the general structure of Vim commands into a simple grammar rule.\n\nThis is the most important chapter in the entire guide. Once you understand the underlying grammatical structure, you will be able to \"speak\" to Vim. By the way, when I say *Vim language* in this chapter, I am not talking about Vimscript language (Vim's built-in programming language, you will learn that in later chapters).\n\n## How to Learn a Language\n\nI am not a native English speaker. I learned English when I was 13 when I moved to the US. There are three things you need to do to learn to speak a new language:\n\n1. Learn grammar rules.\n2. Increase vocabulary.\n3. Practice, practice, practice.\n\nLikewise, to speak Vim language, you need to learn the grammar rules, increase vocabulary, and practice until you can run the commands without thinking.\n\n## Grammar Rule\n\nThere is only one grammar rule in Vim language:\n\n```\nverb + noun\n```\n\nThat's it!\n\nThis is like saying these English phrases:\n\n- *\"Eat (verb) a donut (noun)\"*\n- *\"Kick (verb) a ball (noun)\"*\n- *\"Learn (verb) the Vim editor (noun)\"*\n\nNow you need to build up your vocabulary with basic Vim verbs and nouns.\n\n## Nouns (Motions)\n\nNouns are Vim motions. Motions are used to move around in Vim. Below is a list of some of Vim motions:\n\n```\nh    Left\nj    Down\nk    Up\nl    Right\nw    Move forward to the beginning of the next word\n}    Jump to the next paragraph\n$    Go to the end of the line\n```\n\nYou will learn more about motions in the next chapter, so don't worry too much if you don't understand some of them.\n\n## Verbs (Operators)\n\nAccording to `:h operator`, Vim has 16 operators. However, in my experience, learning these 3 operators is enough for 80% of my editing needs:\n\n```\ny    Yank text (copy)\nd    Delete text and save to register\nc    Delete text, save to register, and start insert mode\n```\n\nBtw, after you yank a text, you can paste it with `p` (after the cursor) or `P` (before the cursor).\n\n## Verb and Noun\n\nNow that you know basic nouns and verbs, let's apply the grammar rule, verb + noun! Suppose you have this expression:\n\n```javascript\nconst learn = \"vim\";\n```\n\n- To yank everything from your current location to the end of the line: `y$`.\n- To delete from your current location to the beginning of the next word: `dw`.\n- To change from your current location to the end of the current paragraph, say `c}`.\n\nMotions also accept count number as arguments (I will discuss this in the next chapter). If you need to go up 3 lines, instead of pressing `k` 3 times, you can do `3k`. Count works with Vim grammar.\n- To yank two characters to the left: `y2h`.\n- To delete the next two words: `d2w`.\n- To change the next two lines: `c2j`.\n\nRight now, you may have to think long and hard to execute even a simple command. You're not alone. When I first started, I had similar struggles but I got faster in time. So will you. Repetition, repetition, repetition.\n\nAs a side note, linewise operations (operations affecting the entire line) are common operations in text editing. In general, by typing an operator command twice, Vim performs a linewise operation for that action. For example, `dd`, `yy`, and `cc` perform **deletion**, **yank**, and **change** on the entire line. Try this with other operators!\n\nThis is really cool. I am seeing a pattern here. But I am not quite done yet. Vim has one more type of noun: text objects.\n\n## More Nouns (Text Objects)\n\nImagine you are somewhere inside a pair of parentheses like `(hello Vim)` and you need to delete the entire phrase inside the parentheses. How can you quickly do it? Is there a way to delete the \"group\" you are inside of?\n\nThe answer is yes. Texts often come structured. They often contain parentheses, quotes, brackets, braces, and more. Vim has a way to capture this structure with text objects.\n\nText objects are used with operators. There are two types of text objects: inner and outer text objects.\n\n```\ni + object    Inner text object\na + object    Outer text object\n```\n\nInner text object selects the object inside *without* the white space or the surrounding objects. Outer text object selects the object inside *including* the white space or the surrounding objects. Generally, an outer text object always selects more text than an inner text object. If your cursor is somewhere inside the parentheses in the expression `(hello Vim)`:\n- To delete the text inside the parentheses without deleting the parentheses: `di(`.\n- To delete the parentheses and the text inside: `da(`.\n\nLet's look at a different example. Suppose you have this Javascript function and your cursor is on the \"H\" in \"Hello\":\n\n```javascript\nconst hello = function() {\n  console.log(\"Hello Vim\");\n  return true;\n}\n```\n\n- To delete the entire \"Hello Vim\": `di(`.\n- To delete the content of function (surrounded by `{}`): `di{`.\n- To delete the \"Hello\" string: `diw`.\n\nText objects are powerful because you can target different objects from one location. You can delete the objects inside the parentheses, the function block, or the current word. Mnemonically, when you see `di(`, `di{`, and `diw`, you get a pretty good idea which text objects they represent: a pair of parentheses, a pair of braces, and a word.\n\nLet's look at one last example. Suppose you have these HTML tags:\n\n```html\n<div>\n  <h1>Header1</h1>\n  <p>Paragraph1</p>\n  <p>Paragraph2</p>\n</div>\n```\n\nIf your cursor is on \"Header1\" text:\n- To delete \"Header1\": `dit`.\n- To delete `<h1>Header1</h1>`: `dat`.\n\nIf your cursor is on \"div\":\n- To delete `h1` and both `p` lines: `dit`.\n- To delete everything: `dat`.\n- To delete \"div\": `di<`.\n\nBelow is a list of common text objects:\n\n```\nw         A word\np         A paragraph\ns         A sentence\n( or )    A pair of ( )\n{ or }    A pair of { }\n[ or ]    A pair of [ ]\n< or >    A pair of < >\nt         XML tags\n\"         A pair of \" \"\n'         A Pair of ' '\n`         A pair of ` `\n```\n\nTo learn more, check out `:h text-objects`.\n\n## Composability and Grammar\n\nVim grammar is a subset of Vim's composability feature. Let's discuss composability in Vim and why this is a great feature to have in a text editor.\n\nComposability means having a set of general commands that can be combined (composed) to perform more complex commands. Just like in programming where you can create more complex abstractions from simpler abstractions, in Vim you can execute complex commands from simpler commands. Vim grammar is the manifestation of Vim's composable nature.\n\nThe true power of Vim's composability shines when it integrates with external programs. Vim has a filter operator (`!`) to use external programs as filters for our texts. Suppose you have this messy text below and you want to tabularize it:\n\n```\nId|Name|Cuteness\n01|Puppy|Very\n02|Kitten|Ok\n03|Bunny|Ok\n```\n\nThis cannot be easily done with Vim commands, but you can get it done quickly with `column` terminal command (assuming your terminal has `column` command). With your cursor on \"Id\", run `!}column -t -s \"|\"`. Voila! Now you have this pretty tabular data with just one quick command.\n\n```\nId  Name    Cuteness\n01  Puppy   Very\n02  Kitten  Ok\n03  Bunny   Ok\n```\n\nLet's break down the command. The verb was `!` (filter operator) and the noun was `}` (go to next paragraph). The filter operator `!` accepted another argument, a terminal command, so I gave it `column -t -s \"|\"`. I won't go through how `column` worked, but in effect, it tabularized the text.\n\nSuppose you want to not only tabularize your text, but to display only the rows with \"Ok\". You know that `awk` can do the job easily. You can do this instead:\n\n```\n!}column -t -s \"|\" | awk 'NR > 1 && /Ok/ {print $0}'\n```\n\nResult:\n\n```\n02  Kitten  Ok\n03  Bunny   Ok\n```\n\nGreat! The external command operator can also use pipe (`|`).\n\nThis is the power of Vim's composability. The more you know your operators, motions, and terminal commands, your ability to compose complex actions is *multiplied*.\n\nSuppose you only know four motions, `w, $, }, G` and only one operator, `d`. You can do 8 actions: *move* 4 different ways (`w, $, }, G`) and *delete* 4 different targets (`dw, d$, d}, dG`). Then one day you learn about the uppercase (`gU`) operator. You have added not just one new ability to your Vim tool belt, but *four*: `gUw, gU$, gU}, gUG`. That makes 12 tools in your Vim tool belt. Each new knowledge is a multiplier to your current abilities. If you know 10 motions and 5 operators, you have 60 moves (50 operations + 10 motions) in your arsenal. Vim has a line-number motion (`nG`) that gives you `n` motions, where `n` is how many lines you have in your file (to go to line 5, run `5G`). The search motion (`/`) practically gives you near unlimited number of motions because you can search for anything. External command operator (`!`) gives you as many filtering tools as the number of terminal commands you know. Using a composable tool like Vim, everything you know can be linked together to do operations with increasing complexity. The more you know, the more powerful you become.\n\nThis composable behavior echoes Unix philosophy: *do one thing well*. An operator has one job: do Y. A motion has one job: go to X. By combining an operator with a motion, you predictably get YX: do Y on X.\n\nMotions and operators are extendable. You can create custom motions and operators to add to your Vim toolbelt. The [`vim-textobj-user`](https://github.com/kana/vim-textobj-user) plugin allows you to create your own text objects. It also contains a [list](https://github.com/kana/vim-textobj-user/wiki) of user-made custom text objects.\n\n## Learn Vim Grammar the Smart Way\n\nYou just learned about Vim grammar's rule: `verb + noun`. One of my biggest Vim \"AHA!\" moment was when I had just learned about the uppercase (`gU`) operator and wanted to uppercase the current word, I *instinctively* ran `gUiw` and it worked! The word was uppercased. At that moment, I finally began to understand Vim. My hope is that you will have your own \"AHA!\" moment soon, if not already.\n\nThe goal of this chapter is to show you the `verb + noun` pattern in Vim so you will approach learning Vim like learning a new language instead of memorizing every command combination.\n\nLearn the pattern and understand the implications. That's the smart way to learn.\n\n## Link\n- Prev [Ch03. Searching Files](./ch03_searching_files.md)\n- Next [Ch05. Moving in a File](./ch05_moving_in_file.md)\n"
  },
  {
    "path": "ch05_moving_in_file.md",
    "content": "# Ch05. Moving in a File\n\nIn the beginning, moving with a keyboard feels slow and awkward but don't give up! Once you get used to it, you can go anywhere in a file faster than using a mouse.\n\nIn this chapter, you will learn the essential motions and how to use them efficiently. Keep in mind that this is **not** the entire motion that Vim has. The goal here is to introduce useful motions to become productive quickly. If you need to learn more, check out `:h motion.txt`.\n\n## Character Navigation\n\nThe most basic motion unit is moving one character left, down, up, and right.\n\n```\nh   Left\nj   Down\nk   Up\nl   Right\ngj  Down in a soft-wrapped line\ngk  Up in a soft-wrapped line\n```\n\nYou can also move with directional arrows. If you are just starting, feel free to use any method you're most comfortable with.\n\nI prefer `hjkl` because my right hand can stay in the home row. Doing this gives me shorter reach to surrounding keys. To get used to `hjkl`, I actually disabled the arrow buttons when starting out by adding these in `~/.vimrc`:\n\n```\nnoremap <Up> <NOP>\nnoremap <Down> <NOP>\nnoremap <Left> <NOP>\nnoremap <Right> <NOP>\n```\n\nThere are also plugins to help break this bad habit. One of them is [vim-hardtime](https://github.com/takac/vim-hardtime). To my surprise, it took me less than a week to get used to `hjkl`.\n\nIf you wonder why Vim uses `hjkl` to move, this is because Lear-Siegler ADM-3A terminal where Bill Joy wrote Vi, didn't have arrow keys and used `hjkl` as left/down/up/right.\n\n## Relative Numbering\n\nI think it is helpful to have `number` and `relativenumber` set. You can do it by having this on `.vimrc`:\n\n```\nset relativenumber number\n```\n\nThis displays my current line number and relative line numbers.\n\nIt is easy why having a number on the left column is useful, but some of you may ask how having relative numbers on the left column may be useful. Having a relative number allows me to quickly see how many lines apart my cursor is from the target text. With this, I can easily spot that my target text is 12 lines below me so I can do `d12j` to delete them. Otherwise, if I'm on line 69 and my target is on line 81, I have to do mental calculation (81 - 69 = 12). Doing math while editing takes too much mental resources. The less I have to think about where I need to go, the better.\n\nThis is 100% personal preference. Experiment with `relativenumber` / `norelativenumber`, `number` / `nonumber` and use whatever you find most useful!\n\n## Count Your Move\n\nLet's talk about the \"count\" argument. Vim motions accept a preceding numerical argument. I mentioned above that you can go down 12 lines with `12j`. The 12 in `12j` is the count number.\n\nThe syntax to use count with your motion is:\n\n```\n[count] + motion\n```\n\nYou can apply this to all motions. If you want to move 9 characters to the right, instead of pressing `l` 9 times, you can do `9l`.\n\n## Word Navigation\n\nLet's move to a larger motion unit: *word*. You can move to the beginning of the next word (`w`), to the end of the next word (`e`), to the beginning of the previous word (`b`), and to the end of the previous word (`ge`).\n\nIn addition, there is *WORD*, distinct from word. You can move to the beginning of the next WORD (`W`), to the end of the next WORD (`E`), to the beginning of the previous WORD (`B`), and to the end of the previous WORD (`gE`). To make it easy to remember, WORD uses the same letters as word, only uppercased.\n\n```\nw     Move forward to the beginning of the next word\nW     Move forward to the beginning of the next WORD\ne     Move forward one word to the end of the next word\nE     Move forward one word to the end of the next WORD\nb     Move backward to beginning of the previous word\nB     Move backward to beginning of the previous WORD\nge    Move backward to end of the previous word\ngE    Move backward to end of the previous WORD\n```\n\nSo what are the similarities and differences between a word and a WORD? Both word and WORD are separated by blank characters. A word is a sequence of characters containing *only* `a-zA-Z0-9_`. A WORD is a sequence of all characters except white space (a white space means either space, tab, and EOL). To learn more, check out `:h word` and `:h WORD`.\n\nFor example, suppose you have:\n\n```\nconst hello = \"world\";\n```\n\nWith your cursor at the start of the line, to go to the end of the line with `l`, it will take you 21 key presses. Using `w`, it will take 6. Using `W`, it will only take 4. Both word and WORD are good options to travel short distance.\n\nHowever, you can get from \"c\" to \";\" in one keystroke with current line navigation.\n\n## Current Line Navigation\n\nWhen editing, you often need to navigate horizontally in a line. To jump to the first character in current line, use `0`. To go to the last character in the current line, use `$`. Additionally, you can use `^` to go to the first non-blank character in the current line and `g_` to go to the last non-blank character in the current line. If you want to go to the column `n` in the current line, you can use `n|`.\n\n```\n0     Go to the first character in the current line\n^     Go to the first nonblank char in the current line\ng_    Go to the last non-blank char in the current line\n$     Go to the last char in the current line\nn|    Go to the column n in the current line\n```\n\nYou can do current line search with `f` and `t`. The difference between `f` and `t` is that `f` takes you to the first letter of the match and `t` takes you till (right before) the first letter of the match. So if you want to search for \"h\" and land on \"h\", use `fh`. If you want to search for first \"h\" and land right before the match, use `th`. If you want to go to the *next* occurrence of the last current line search, use `;`. To go to the previous occurrence of the last current line match, use `,`.\n\n`F` and `T` are the backward counterparts of `f` and `t`. To search backwards for \"h\", run `Fh`. To keep searching for \"h\" in the same direction, use `;`. Note that `;` after a `Fh` searches backward and `,` after `Fh` searches forward. \n\n```\nf    Search forward for a match in the same line\nF    Search backward for a match in the same line\nt    Search forward for a match in the same line, stopping before match\nT    Search backward for a match in the same line, stopping before match\n;    Repeat the last search in the same line using the same direction\n,    Repeat the last search in the same line using the opposite direction\n```\n\nBack at the previous example:\n\n```\nconst hello = \"world\";\n```\n\nWith your cursor at the start of the line, you can go to the last character in current line (\";\") with one keypress: `$`. If you want to go to \"w\" in \"world\", you can use `fw`. A good tip to go anywhere in a line is to look for least-common-letters like \"j\", \"x\", \"z\" near your target.\n\n## Sentence and Paragraph Navigation\n\nNext two navigation units are sentence and paragraph.\n\nLet's talk about what a sentence is first. A sentence ends with either `. ! ?` followed by an EOL, a space, or a tab.  You can jump to the next sentence with `)` and the previous sentence with `(`.\n\n```\n(    Jump to the previous sentence\n)    Jump to the next sentence\n```\n\nLet's look at some examples. Which phrases do you think are sentences and which aren't? Try navigating with `(` and `)` in Vim!\n\n```\nI am a sentence. I am another sentence because I end with a period. I am still a sentence when ending with an exclamation point! What about question mark? I am not quite a sentence because of the hyphen - and neither semicolon ; nor colon :\n\nThere is an empty line above me.\n```\n\nBy the way, if you're having a problem with Vim not counting a sentence for phrases separated by `.` followed by a single line, you might be in `'compatible'` mode. Add `set nocompatible` into vimrc. In Vi, a sentence is a `.` followed by **two** spaces. You should have `nocompatible` set at all times.\n\nLet's talk about what a paragraph is. A paragraph begins after each empty line and also at each set of a paragraph macro specified by the pairs of characters in paragraphs option.\n\n```\n{    Jump to the previous paragraph\n}    Jump to the next paragraph\n```\n\nIf you're not sure what a paragraph macro is, do not worry. The important thing is that a paragraph begins and ends after an empty line. This should be true most of the time.\n\nLet's look at this example. Try navigating around with `}` and `{` (also, play around with sentence navigations `( )` to move around too!)\n\n```\nHello. How are you? I am great, thanks!\nVim is awesome.\nIt may not be easy to learn it at first...- but we are in this together. Good luck!\n\nHello again.\n\nTry to move around with ), (, }, and {. Feel how they work.\nYou got this.\n```\n\nCheck out `:h sentence` and `:h paragraph` to learn more.\n\n## Match Navigation\n\nProgrammers write and edit code. Code typically uses parentheses, braces, and brackets. You can easily get lost in them. If you're inside one, you can jump to the other pair (if it exists) with `%`. You can also use this to find out whether you have matching parentheses, braces, and brackets.\n\n```\n%    Navigate to another match, usually works for (), [], {}\n```\n\nLet's look at a Scheme code example because it uses parentheses extensively. Move around with `%` inside different parentheses.\n\n```\n(define (fib n)\n  (cond ((= n 0) 0)\n        ((= n 1) 1)\n        (else\n          (+ (fib (- n 1)) (fib (- n 2)))\n        )))\n```\n\nI personally like to complement `%` with visual indicators plugins like [vim-rainbow](https://github.com/frazrepo/vim-rainbow). For more, check out `:h %`.\n\n## Line Number Navigation\n\nYou can jump to line number `n` with `nG`. For example, if you want to jump to line 7, use `7G`. To jump to the first line, use either `1G` or `gg`. To jump to the last line, use `G`.\n\nOften you don't know exactly what line number your target is, but you know it's approximately at 70% of the whole file. In this case, you can do `70%`. To jump halfway through the file, you can do `50%`.\n\n```\ngg    Go to the first line\nG     Go to the last line\nnG    Go to line n\nn%    Go to n% in file\n```\n\nBy the way, if you want to see total lines in a file, you can use `Ctrl-g`.\n\n## Window Navigation\n\nTo quickly go to the top, middle, or bottom of your *window*, you can use `H`, `M`, and `L`.\n\nYou can also pass a count to `H` and `L`. If you use `10H`, you will go to 10 lines below the top of window. If you use `3L`, you will go to 3 lines above the last line of window.\n\n```\nH     Go to top of screen\nM     Go to medium screen\nL     Go to bottom of screen\nnH    Go n line from top\nnL    Go n line from bottom\n```\n\n## Scrolling\n\nTo scroll, you have 3 speed increments: full-screen (`Ctrl-F/Ctrl-B`), half-screen (`Ctrl-D/Ctrl-U`), and line (`Ctrl-E/Ctrl-Y`).\n\n```\nCtrl-E    Scroll down a line\nCtrl-D    Scroll down half screen\nCtrl-F    Scroll down whole screen\nCtrl-Y    Scroll up a line\nCtrl-U    Scroll up half screen\nCtrl-B    Scroll up whole screen\n```\n\nYou can also scroll relatively to the current line (zoom screen sight):\n\n```\nzt    Bring the current line near the top of your screen\nzz    Bring the current line to the middle of your screen\nzb    Bring the current line near the bottom of your screen\n```\n\n## Search Navigation\n\nOften you know that a phrase exists inside a file. You can use search navigation to very quickly reach your target. To search for a phrase, you can use `/` to search forward and `?` to search backward. To repeat the last search you can use `n`. To repeat the last search going opposite direction, you can use `N`.\n\n```\n/    Search forward for a match\n?    Search backward for a match\nn    Repeat last search in same direction of previous search\nN    Repeat last search in opposite direction of previous search\n```\n\nSuppose you have this text:\n\n```\nlet one = 1;\nlet two = 2;\none = \"01\";\none = \"one\";\nlet onetwo = 12;\n```\n\nIf you are searching for \"let\", run `/let`. To quickly search for \"let\" again, you can just do `n`. To search for \"let\" again in opposite direction, run `N`. If you run `?let`, it will search for \"let\" backwards. If you use `n`, it will now search for \"let\" backwards (`N` will search for \"let\" forwards now).\n\nYou can enable search highlight with `set hlsearch`. Now when you search for `/let`, it will highlight *all* matching phrases in the file. In addition, you can set incremental search with `set incsearch`. This will highlight the pattern while typing. By default, your matching phrases will remain highlighted until you search for another phrase. This can quickly turn into an annoyance. To disable highlight, you can run `:nohlsearch` or simply `:noh`. Because I use this no-highlight feature frequently, I created a map in vimrc:\n\n```\nnnoremap <esc><esc> :noh<return><esc>\n```\n\nYou can quickly search for the text under the cursor with `*` to search forward and `#` to search backward. If your cursor is on the string \"one\", pressing `*` will be the same as if you had done `/\\<one\\>`.\n\nBoth `\\<` and `\\>` in `/\\<one\\>` mean whole word search. It does not match \"one\" if it is a part of a bigger word. It will match for the word \"one\" but not \"onetwo\".  If your cursor is over \"one\" and you want to search forward to match whole or partial words like \"one\" and \"onetwo\", you need to use `g*` instead of `*`.\n\n```\n*     Search for whole word under cursor forward\n#     Search for whole word under cursor backward\ng*    Search for word under cursor forward\ng#    Search for word under cursor backward\n\n```\n## Marking Position\n\nYou can use marks to save your current position and return to this position later. It's like a bookmark for text editing. You can set a mark with `mx`, where `x` can be any alphabetical letter `a-zA-Z`. There are two ways to return to mark: exact (line and column) with `` `x`` and linewise (`'x`).\n\n```\nma    Mark position with mark \"a\"\n`a    Jump to line and column \"a\"\n'a    Jump to line \"a\"\n```\n\nThere is a difference between marking with lowercase letters (a-z) and uppercase letters (A-Z). Lowercase alphabets are local marks and uppercase alphabets are global marks (sometimes known as file marks).\n\nLet's talk about local marks. Each buffer can have its own set of local marks. If I have two files opened, I can set a mark \"a\" (`ma`)  in the first file and another mark \"a\" (`ma`) in the second file.\n\nUnlike local marks where you can have a set of marks in each buffer, you only get one set of global marks. If you set `mA` inside `myFile.txt`, the next time you run `mA` in a different file, it will overwrite the first \"A\" mark. One advantage of global marks is you can jump to any global mark even if you are inside a completely different project. Global marks can travel across files.\n\nTo view all marks, use `:marks`. You may notice from the marks list there are more marks other than `a-zA-Z`. Some of them are:\n\n```\n''    Jump back to the last line in current buffer before jump\n``    Jump back to the last position in current buffer before jump\n`[    Jump to beginning of previously changed / yanked text\n`]    Jump to the ending of previously changed / yanked text\n`<    Jump to the beginning of last visual selection\n`>    Jump to the ending of last visual selection\n`0    Jump back to the last edited file when exiting vim\n```\n\nThere are more marks than the ones listed above. I won't cover them here because I think they are rarely used, but if you're curious, check out `:h marks`.\n\n## Jump\n\nIn Vim, you can \"jump\" to a different file or different part of a file with some motions. Not all motions count as a jump, though. Going down with `j` does not count as a jump. Going to line 10 with `10G` counts as a jump.\n\nHere are the commands Vim considers as \"jump\" commands:\n\n```\n'       Go to the marked line\n`       Go to the marked position\nG       Go to the line\n/       Search forward\n?       Search backward\nn       Repeat the last search, same direction\nN       Repeat the last search, opposite direction\n%       Find match\n(       Go to the last sentence\n)       Go to the next sentence\n{       Go to the last paragraph\n}       Go to the next paragraph\nL       Go to the last line of displayed window\nM       Go to the middle line of displayed window\nH       Go to the top line of displayed window\n[[      Go to the previous section\n]]      Go to the next section\n:s      Substitute\n:tag    Jump to tag definition\n```\n\nI don't recommend memorizing this list. A good rule of thumb is, any motion that moves farther than a word and current line navigation is probably a jump. Vim keeps track of where you've been when you move around and you can see this list inside `:jumps`. \n\nFor more, check out `:h jump-motions`.\n\nWhy are jumps useful? Because you can navigate the jump list with `Ctrl-O` to move up the jump list and `Ctrl-I` to move down the jump list. `hjkl` are not \"jump\" commands, but you can manually add the current location to jump list with `m'` before movement. For example, `m'5j` adds current location to jump list and goes down 5 lines, and you can come back with `Ctrl-O`. You can jump across different files, which I will discuss more in the next part.\n\n## Learn Navigation the Smart Way\n\nIf you are new to Vim, this is a lot to learn. I do not expect anyone to remember everything immediately. It takes time before you can execute them without thinking.\n\nI think the best way to get started is to memorize a few essential motions. I recommend starting out with these 10 motions: `h, j, k, l, w, b, G, /, ?, n`. Repeat them sufficiently until you can use them without thinking.\n\nTo improve your navigation skill, here are my suggestions:\n1. Watch for repeated actions. If you find yourself doing `l` repeatedly, look for a motion that will take you forward faster. You will find that you can use `w`. If you catch yourself repeatedly doing `w`, look if there is a motion that will take you across the current line quickly. You will find that you can use the `f`. If you can describe your need succinctly, there is a good chance Vim has a way to do it.\n2. Whenever you learn a new move, spend some time until you can do it without thinking.\n\nFinally, realize that you do not need to know every single Vim command to be productive. Most Vim users don't. I don't. Learn the commands that will help you accomplish your task at that moment.\n\nTake your time. Navigation skill is a very important skill in Vim. Learn one small thing every day and learn it well.\n\n## Link\n- Prev [Ch04. Vim Grammar](./ch04_vim_grammar.md)\n- Next [Ch06. Insert Mode](./ch06_insert_mode.md)\n"
  },
  {
    "path": "ch06_insert_mode.md",
    "content": "# Ch06. Insert Mode\n\nInsert mode is the default mode of many text editors. In this mode, what you type is what you get.\n\nHowever, that does not mean there isn't much to learn. Vim's insert mode contains many useful features. In this chapter, you will learn how to use these insert mode features in Vim to improve your typing efficiency.\n\n## Ways to Go to Insert Mode\n\nThere are many ways to get into insert mode from the normal mode. Here are some of them:\n\n```\ni    Insert text before the cursor\nI    Insert text before the first non-blank character of the line\na    Append text after the cursor\nA    Append text at the end of line\no    Starts a new line below the cursor and insert text\nO    Starts a new line above the cursor and insert text\ns    Delete the character under the cursor and insert text\nS    Delete the current line and insert text, synonym for \"cc\"\ngi   Insert text in same position where the last insert mode was stopped\ngI   Insert text at the start of line (column 1)\n```\n\nNotice the lowercase / uppercase pattern. For each lowercase command, there is an uppercase counterpart. If you are new, don't worry if you don't remember the whole list above. Start with `i` and `o`. They should be enough to get you started. Gradually learn more over time.\n\n## Different Ways to Exit Insert Mode\n\nThere are a few different ways to return to the normal mode while in the insert mode:\n\n```\n<Esc>     Exits insert mode and go to normal mode\nCtrl-[    Exits insert mode and go to normal mode\nCtrl-C    Like Ctrl-[ and <Esc>, but does not check for abbreviation\n```\n\nI find `<Esc>` key too far to reach, so I map my computer `<Caps-Lock>` to behave like `<Esc>`. If you search for Bill Joy's ADM-3A keyboard (Vi creator), you will see that the `<Esc>` key is not located on far top left like modern keyboards, but to the left of `q` key. This is why I think it makes sense to map  `<Caps lock>` to `<Esc>`.\n\nAnother common convention I have seen Vim users do is mapping `<Esc>` to `jj` or `jk` in insert mode. If you prefer this option, add one of those lines (or both) in your vimrc file.\n\n```\ninoremap jj <Esc>\ninoremap jk <Esc>\n```\n\n## Repeating Insert Mode\n\nYou can pass a count parameter before entering insert mode. For example:\n\n```\n10i\n```\n\nIf you type \"hello world!\" and exit insert mode, Vim will repeat the text 10 times. This will work with any insert mode method (ex: `10I`, `11a`, `12o`).\n\n## Deleting Chunks in Insert Mode\n\nWhen you make a typing mistake, it can be cumbersome to type `<Backspace>` repeatedly. It may make more sense to go to normal mode and delete your mistake. You can also delete several characters at a time while in insert mode.\n\n```\nCtrl-h    Delete one character\nCtrl-w    Delete one word\nCtrl-u    Delete the entire line\n```\n\n## Insert From Register\n\nVim registers can store texts for future use. To insert a text from any named register while in insert mode, type `Ctrl-R` plus the register symbol. There are many symbols you can use, but for this section, let's cover only the named registers (a-z).\n\nTo see it in action, first you need to yank a word to register a. Move your cursor on any word. Then type:\n\n```\n\"ayiw\n```\n\n- `\"a` tells Vim that the target of your next action will go to register a.\n- `yiw` yanks inner word. Review the chapter on Vim grammar for a refresher.\n\nRegister a now contains the word you just yanked. While in insert mode, to paste the text stored in register a:\n\n```\nCtrl-R a\n```\n\nThere are multiple types of registers in Vim. I will cover them in greater detail in a later chapter.\n\n## Scrolling\n\nDid you know that you can scroll while inside insert mode? While in insert mode, if you go to `Ctrl-X` sub-mode, you can do additional operations. Scrolling is one of them.\n\n```\nCtrl-X Ctrl-Y    Scroll up\nCtrl-X Ctrl-E    Scroll down\n```\n\n## Autocompletion\n\nAs mentioned above, if you press `Ctrl-X` from insert mode, Vim will enter a sub-mode. You can do text autocompletion while in this insert mode sub-mode. Although it is not as good as [intellisense](https://code.visualstudio.com/docs/editor/intellisense) or any other Language Server Protocol (LSP), for something that is available right out of the box, it is a very capable feature.\n\nHere are some useful autocomplete commands to get started:\n\n```\nCtrl-X Ctrl-L\t   Insert a whole line\nCtrl-X Ctrl-N\t   Insert a text from current file\nCtrl-X Ctrl-I\t   Insert a text from included files\nCtrl-X Ctrl-F\t   Insert a file name\n```\n\nWhen you trigger autocompletion, Vim will display a pop-up window. To navigate up and down the pop-up window, use `Ctrl-N` and `Ctrl-P`.\n\nVim also has two autocompletion shortcuts that don't involve the `Ctrl-X` sub-mode:\n\n```\nCtrl-N             Find the next word match\nCtrl-P             Find the previous word match\n```\n\nIn general, Vim looks at the text in all available buffers for autocompletion source. If you have an open buffer with a line that says \"Chocolate donuts are the best\":\n- When you type \"Choco\" and do `Ctrl-X Ctrl-L`, it will match and print the entire line.\n- When you type \"Choco\" and do `Ctrl-P`, it will match and print the word \"Chocolate\".\n\nAutocomplete is a vast topic in Vim. This is just the tip of the iceberg. To learn more, check out `:h ins-completion`.\n\n## Executing a Normal Mode Command\n\nDid you know Vim can execute a normal mode command while in insert mode?\n\nWhile in insert mode, if you press `Ctrl-O`, you'll be in insert-normal sub-mode. If you look at the mode indicator on bottom left, normally you will see `-- INSERT --`, but pressing `Ctrl-O`  changes it to `-- (insert) --`. In this mode, you can do *one* normal mode command. Some things you can do:\n\n**Centering and jumping**\n\n```\nCtrl-O zz       Center window\nCtrl-O H/M/L    Jump to top/middle/bottom window\nCtrl-O 'a       Jump to mark a\n```\n\n**Repeating text**\n\n```\nCtrl-O 100ihello    Insert \"hello\" 100 times\n```\n\n**Executing terminal commands**\n\n```\nCtrl-O !! curl https://google.com    Run curl\nCtrl-O !! pwd                        Run pwd\n```\n\n**Deleting faster**\n\n```\nCtrl-O dtz    Delete from current location till the letter \"z\"\nCtrl-O D      Delete from current location to the end of the line\n```\n\n## Learn Insert Mode the Smart Way\n\nIf you are like me and you come from another text editor, it can be tempting to stay in insert mode. However, staying in insert mode when you're not entering a text is an anti-pattern. Develop a habit to go to normal mode when your fingers aren't typing new text.\n\nWhen you need to insert a text, first ask yourself if that text already exists. If it does, try to yank or move that text instead of typing it. If you have to use insert mode, see if you can autocomplete that text whenever possible. Avoid typing the same word more than once if you can.\n\n## Link\n- Prev [Ch05. Moving in a File](./ch05_moving_in_file.md)\n- Next [Ch07. The Dot Command](./ch07_the_dot_command.md)\n"
  },
  {
    "path": "ch07_the_dot_command.md",
    "content": "# Ch07. The Dot Command\n\nIn general, you should try to avoid redoing what you just did whenever possible. In this chapter, you will learn how to use the dot command to easily redo the previous change. It is a versatile command for reducing simple repetitions.\n\n## Usage\n\nJust like its name, you can use the dot command by pressing the dot key (`.`).\n\nFor example, if you want to replace all \"let\" with \"const\" in the following expressions:\n\n```\nlet one = \"1\";\nlet two = \"2\";\nlet three = \"3\";\n```\n\n- Search with `/let` to go to the match.\n- Change with `cwconst<Esc>` to replace \"let\" with \"const\".\n- Navigate with `n` to find the next match using the previous search.\n- Repeat what you just did with the dot command (`.`).\n- Continue pressing `n . n .` until you replace every word.\n\nHere the dot command repeated the `cwconst<Esc>` sequence. It saved you from typing eight keystrokes in exchange for just one.\n\n## What Is a Change?\n\nIf you look at the definition of the dot command (`:h .`), it says that the dot command repeats the last change. What is a change?\n\nAny time you update (add, modify, or delete) the content of the current buffer, you are making a change. The exceptions are updates done by command-line commands (the commands starting with `:`), which do not count as a change.\n\nIn the first example, `cwconst<Esc>` was the change. Now suppose you have this text:\n\n```\npancake, potatoes, fruit-juice,\n```\n\nTo delete the text from the start of the line to the next occurrence of a comma, first delete to the comma, then repeat it twice with `df,..`. \n\nLet's try another example:\n\n```\npancake, potatoes, fruit-juice,\n```\n\nThis time, your task is to delete the comma, not the breakfast items. With the cursor at the beginning of the line, go to the first comma, delete it, then repeat two more times with `f,x..` Easy, right? Wait a minute, it didn't work! Why?\n\nA change excludes motions because it does not update buffer content. The command `f,x` consisted of two actions: the command `f,` to move the cursor to \",\" and `x` to delete a character. Only the latter, `x`, caused a change. Contrast that with `df,` from the earlier example. In it, `f,` is a directive to the delete operator `d`, not a motion to move the cursor. The `f,` in `df,` and `f,x` have two very different roles.\n\nLet's finish the last task. After you run `f,` then `x`, go to the next comma with `;` to repeat the latest `f`. Finally, use `.` to delete the character under the cursor. Repeat `; . ; .` until everything is deleted. The full command is `f,x;.;.`.\n\nLet's try another one:\n\n```\npancake\npotatoes\nfruit-juice\n```\n\nLet's add a comma at the end of each line. Starting at the first line, do `A,<Esc>j`. By now, you realize that `j` does not cause a change. The change here is only `A,`. You can move and repeat the change with `j . j .`. The full command is `A,<Esc>j.j.`.\n\nEvery action from the moment you press the insert command operator (`A`) until you exit the insert command (`<Esc>`) is considered as a change.\n\n## Multi-line Repeat\n\nSuppose you have this text:\n\n```\nlet one = \"1\";\nlet two = \"2\";\nlet three = \"3\";\nconst foo = \"bar';\nlet four = \"4\";\nlet five = \"5\";\nlet six = \"6\";\nlet seven = \"7\";\nlet eight = \"8\";\nlet nine = \"9\";\n```\n\nYour goal is to delete all lines except the \"foo\" line. First, delete the first three lines with `d2j`, then to the line below the \"foo\" line. On the next line, use the dot command twice. The full command is `d2jj..`.\n\nHere the change was `d2j`. In this context, `2j` was not a motion, but a part of the delete operator.\n\nLet's look at another example:\n\n```\nzlet zzone = \"1\";\nzlet zztwo = \"2\";\nzlet zzthree = \"3\";\nlet four = \"4\";\n```\n\nLet's remove all the z's. Starting from the first character on the first line, visually select only the first z from the first three lines with blockwise visual mode (`Ctrl-Vjj`). If you're not familiar with blockwise visual mode, I will cover them in a later chapter. Once you have the three z's visually selected, delete them with the delete operator (`d`). Then move to the next word (`w`) to the next z. Repeat the change two more times (`..`). The full command is `Ctrl-vjjdw..`.\n\nWhen you deleted a column of three z's (`Ctrl-vjjd`), it was counted as a change. Visual mode operation can be used to target multiple lines as part of a change.\n\nIf `Ctrl-V` doesn't switch the window to VISUAL BLOCK mode, you can try (`Ctrl-Q`), read more at: [Ctrl-V don't work in WLS](https://vi.stackexchange.com/questions/12227/vim-v-visual-block-mode-not-working).\n\n## Including a Motion in a Change\n\nLet's revisit the first example in this chapter. Recall that the command `/letcwconst<Esc>` followed by `n . n .`  replaced all \"let\" with \"const\" in the following expressions:\n\n```\nlet one = \"1\";\nlet two = \"2\";\nlet three = \"3\";\n```\n\nThere is a faster way to accomplish this. After you searched `/let`, run `cgnconst<Esc>` then `. .`.\n\n`gn` is a motion that searches forward for the last search pattern (in this case, `/let`) and automatically does a visual highlight. To replace the next occurrence, you no longer have to move and repeat the change ( `n . n .`), but only repeat (`. .`). You do not have to use search motions anymore because searching the next match is now part of the change!\n\nWhen you are editing, always be on the lookout for motions that can do several things at once like `gn` whenever possible.\n\n## Learn the Dot Command the Smart Way\n\nThe dot command's power comes from exchanging several keystrokes for one. It is probably not a profitable exchange to use the dot command for single key operations like `x`. If your last change requires a complex operation like `cgnconst<Esc>`, the dot command reduces nine keypresses into one, a very profitable trade-off.\n\nWhen editing, think about repeatability. For example, if I need to remove the next three words, is it more economical to use `d3w` or to do `dw` then `.` two times? Will you be deleting a word again? If so, then it makes sense to use `dw` and repeat it several times instead of `d3w` because `dw` is more reusable than `d3w`. \n\nThe dot command is a versatile command for automating single changes. In a later chapter, you will learn how to automate more complex actions with Vim macros. But first, let's learn about registers to store and retrieve text.\n\n## Link\n- Prev [Ch06. Insert Mode](./ch06_insert_mode.md)\n- Next [Ch08. Registers](./ch08_registers.md)\n"
  },
  {
    "path": "ch08_registers.md",
    "content": "# Ch08. Registers\n\nLearning Vim registers is like learning algebra for the first time. You didn't think you needed it until you needed it.\n\nYou've probably used Vim registers when you yanked or deleted a text then pasted it with `p` or `P`. However, did you know that Vim has 10 different types of registers? Used correctly, Vim registers can save you from repetitive typing.\n\nIn this chapter, I will go over all Vim register types and how to use them efficiently.\n\n## The Ten Register Types\n\nHere are the 10 Vim register types:\n\n1. The unnamed register (`\"\"`).\n2. The numbered registers (`\"0-9`).\n3. The small delete register (`\"-`).\n4. The named registers (`\"a-z`).\n5. The read-only registers (`\":`, `\".`, and `\"%`).\n6. The alternate file register (`\"#`).\n7. The expression register (`\"=`).\n8. The selection registers (`\"*` and `\"+`).\n9. The black hole register (`\"_`).\n10. The last search pattern register (`\"/`).\n\n\n## Register Operators\n\nTo use registers, you need to first store them with operators. Here are some operators that store values to registers:\n\n```\ny    Yank (copy)\nc    Delete text and start insert mode\nd    Delete text\n```\n\nThere are more operators (like `s` or `x`), but the above are the useful ones. The rule of thumb is, if an operator can remove a text, it probably stores the text to registers.\n\nTo paste a text from registers, you can use:\n\n```\np    Paste the text after the cursor\nP    Paste the text before the cursor\n```\n\nBoth `p` and `P` accept a count and a register symbol as arguments. For example, to paste ten times, do `10p`. To paste the text from register a, do `\"ap`. To paste the text from register a ten times, do `10\"ap`. By the way, the `p` actually technically stands for \"put\", not \"paste\", but I figure paste is a more conventional word.\n\nThe general syntax to get the content from a specific register is `\"a`, where `a` is the register symbol.\n\n## Calling Registers From Insert Mode\n\nEverything you learn in this chapter can also be executed in insert mode. To get the text from register a, normally you do `\"ap`. But if you are in insert mode, run `Ctrl-R a`. The syntax to call registers from insert mode is:\n\n```\nCtrl-R a\n```\n\nWhere `a` is the register symbol. Now that you know how to store and retrieve registers, let's dive in!\n\n\n## The Unnamed Register\n\nTo get the text from the unnamed register, do `\"\"p`. It stores the last text you yanked, changed, or deleted. If you do another yank, change, or delete, Vim will automatically replace the old text. The unnamed register is like a computer's standard copy / paste operation.\n\nBy default, `p` (or `P`) is connected to the unnamed register (from now on I will refer to the unnamed register with `p` instead of `\"\"p`).\n\n## The Numbered Registers\n\nNumbered registers automatically fill themselves up in ascending order. There are 2 different numbered registers: the yanked register (`0`) and the numbered registers (`1-9`). Let's discuss the yanked register first.\n\n### The Yanked Register\n\nIf you yank, Vim actually saves that text in two registers:\n\n1. The unnamed register (`p`).\n2. The yanked register (`\"0p`).\n\nWhen you yank a different text, Vim will update both the yanked register and the unnamed register. Any other operations (like delete) will not be stored in register 0. This can be used to your advantage, because unless you do another yank, the yanked text will always be there, no matter how many changes and deletions you do.\n\nFor example, if you:\n1. Yank a line (`yy`)\n2. Delete a line (`dd`)\n3. Delete another line (`dd`)\n\nThe yanked register will have the text from step one.\n\nIf you:\n1. Yank a line (`yy`)\n2. Delete a line (`dd`)\n3. Yank a word (`yw`)\n\nThe yanked register will have the text from step three.\n\nOne last tip, while in insert mode, you can quickly paste the text you just yanked using `Ctrl-R 0`.\n\n### The Non-zero Numbered Registers\n\nWhen you change or delete a text that is at least one line long, that text will be stored in the numbered registers 1-9 sorted by the most recent.\n\nFor example, if you have these lines:\n\n```\nline three\nline two\nline one\n```\n\nWith your cursor on \"line three\", delete them one by one with `dd`. Once all lines are deleted, register 1 should contain \"line one\" (most recent), register two \"line two\" (second most recent), and register three \"line three\" (oldest). To get the content from register one, do `\"1p`.\n\nAs a side note, these numbered registers are automatically incremented when using the dot command. If your numbered register one (`\"1`) contains \"line one\", register two (`\"2`) \"line two\", and register three (`\"3`) \"line three\", you can paste them sequentially with this trick:\n- Do `\"1P` to paste the content from the numbered register one (\"1).\n- Do `.` to paste the content from the numbered register two (\"2).\n- Do `.` to paste the content from the numbered register three (\"3).\n\nThis trick works with any numbered register. If you started with `\"5P`,  `.`  would do `\"6P`, `.` again would do `\"7P`, and so on.\n\nSmall deletions like a word deletion (`dw`) or word change (`cw`) do not get stored in the numbered registers. They are stored in the small delete register (`\"-`), which I will discuss next.\n\n## The Small Delete Register\n\nChanges or deletions less than one line are not stored in the numbered registers 0-9, but in the small delete register (`\"-`).\n\nFor example:\n1. Delete a word (`diw`)\n2. Delete a line (`dd`)\n3. Delete a line (`dd`)\n\n`\"-p` gives you the deleted word from step one.\n\nAnother example:\n1. I delete a word (`diw`)\n2. I delete a line (`dd`)\n3. I delete a word (`diw`)\n\n`\"-p` gives you the deleted word from step three. `\"1p` gives you the deleted line from step two. Unfortunately, there is no way to retrieve the deleted word from step one because the small delete register only stores one item. However, if you want to preserve the text from step one, you can do it with the named registers.\n\n## The Named Register\n\nThe named registers are Vim's most versatile register. It can store yanked, changed, and deleted texts into registers a-z. Unlike the previous 3 register types you've seen which automatically stores texts into registers, you have to explicitly tell Vim to use the named register, giving you full control.\n\nTo yank a word into register a, you can do it with `\"ayiw`.\n- `\"a` tells Vim that the next action (delete / change / yank) will be stored in register a.\n- `yiw` yanks the word.\n\nTo get the text from register a, run `\"ap`. You can use all twenty-six alphabetical characters to store twenty-six different texts with named registers.\n\nSometimes you may want to add to your existing named register. In this case, you can append your text instead of starting all over. To do that, you can use the uppercase version of that register. For example, suppose you have the word \"Hello \" already stored in register a. If you want to add \"world\" into register a, you can find the text \"world\" and yank it using A register (`\"Ayiw`).\n\n## The Read-only Registers\n\nVim has three read-only registers: `.`, `:`, and `%`. They are pretty simple to use:\n\n```\n.    Stores the last inserted text\n:    Stores the last executed command-line\n%    Stores the name of current file\n```\n\nIf the last text you wrote was \"Hello Vim\", running `\".p` will print out the text \"Hello Vim\". If you want to get the name of current file, run `\"%p`. If you run `:s/foo/bar/g` command, running `\":p` will print out the literal text \"s/foo/bar/g\".\n\n## The Alternate File Register\n\nIn Vim, `#` usually represents the alternate file. An alternative file is the last file you opened. To insert the name of the alternate file, you can use `\"#p`.\n\n## The Expression Register\n\nVim has an expression register, `\"=`, to evaluate expressions.\n\nTo evaluate mathematical expressions `1 + 1`, run:\n\n```\n\"=1+1<Enter>p\n```\n\nHere, you are telling Vim that you are using the expression register with `\"=`. Your expression is (`1 + 1`). You need to type `p` to get the result. As mentioned earlier, you can also access the register from insert mode. To evaluate mathematical expression from insert mode, you can do:\n\n```\nCtrl-R =1+1\n```\n\nYou can also get the values from any register via the expression register when appended with `@`. If you wish to get the text from register a:\n\n```\n\"=@a\n```\n\nThen press `<Enter>`, then `p`. Similarly, to get values from register a while in insert mode:\n\n```\nCtrl-r =@a\n```\n\nExpression is a vast topic in Vim, so I will only cover the basics here. I will address expressions in more detail in later Vimscript chapters.\n\n## The Selection Registers\n\nDon't you sometimes wish that you can copy a text from external programs and paste it locally in Vim, and vice versa? With Vim's selection registers, you can. Vim has two selection registers: `quotestar` (`\"*`) and `quoteplus` (`\"+`). You can use them to access copied text from external programs.\n\nIf you are on an external program (like Chrome browser) and you copy a block of text with `Ctrl-C` (or `Cmd-C`, depending on your OS), normally you wouldn't be able to use `p` to paste the text in Vim. However, both Vim's `\"+` and `\"*` are connected to your clipboard, so you can actually paste the text with  `\"+p` or `\"*p`. Conversely, if you yank a word from Vim with `\"+yiw` or `\"*yiw`, you can paste that text in the external program with `Ctrl-V` (or `Cmd-V`). Note that this only works if your Vim program comes with the `+clipboard` option (to check it, run `:version`).\n\nYou may wonder if `\"*` and `\"+` do the same thing, why does Vim have two different registers? Some machines use X11 window system. This system has 3 types of selections: primary, secondary, and clipboard. If your machine uses X11, Vim uses X11's *primary* selection with the `quotestar` (`\"*`) register and X11's *clipboard* selection with the `quoteplus` (`\"+`) register. This is only applicable if you have `+xterm_clipboard` option available in your Vim build. If your Vim doesn't have `xterm_clipboard`, it's not a big deal. It just means that both `quotestar` and `quoteplus` are interchangeable (mine doesn't either).\n\nI find doing `=*p` or `=+p` (or `\"*p` or `\"+p`) to be cumbersome. To make Vim paste copied text from the external program with just `p`, you can add this in your vimrc:\n\n```\nset clipboard=unnamed\n ```\n\nNow when I copy a text from an external program, I can paste it with the unnamed register, `p`. I can also copy a text from Vim and paste it to an external program. If you have `+xterm_clipboard` on, you may want to use both `unnamed` and `unnamedplus` clipboard options.\n\n## The Black Hole Register\n\nEach time you delete or change a text, that text is stored in Vim register automatically. There will be times when you don't want to save anything into the register. How can you do that?\n\nYou can use the black hole register (`\"_`). To delete a line and not have Vim store the deleted line into any register, use `\"_dd`.\n\nThe black hole register is like the `/dev/null` of registers.\n\n## The Last Search Pattern Register\n\nTo paste your last search (`/` or `?`), you can use the last search pattern register (`\"/`). To paste the last search term, use `\"/p`.\n\n## Viewing the Registers\n\nTo view all your registers, use the `:register` command. To view only registers \"a, \"1, and \"-, use `:register a 1 -`.\n\nThere is a plugin called [vim-peekaboo](https://github.com/junegunn/vim-peekaboo) that lets you peek into the contents of the registers when you hit `\"` or `@` in normal mode and `Ctrl-R` in insert mode. I find this plugin very useful because most times, I can't remember the content in my registers. Give it a try!\n\n## Executing a Register\n\nThe named registers are not just for storing texts. They can also execute macros with `@`. I will go over macros in the next chapter.\n\nKeep in mind since macros are stored inside Vim registers, you can accidentally overwrite the stored text with macros. If you store the text \"Hello Vim\" in register a and you later record a macro in the same register (`qa{macro-sequence}q`), that macro will overwrite your \"Hello Vim\" text stored earlier.\n\n## Clearing a Register\n\nTechnically, there is no need to clear any register because the next text that you store under the same register name will overwrite it. However, you can quickly clear any named register by recording an empty macro. For example, if you run `qaq`, Vim will record an empty macro in the register a.\n\nAnother alternative is to run the command `:call setreg('a', 'hello register a')` where a is the register a and \"hello register a\" is the text that you want to store.\n\nOne more way to clear register is to set the content of \"a register to an empty string with the expression `:let @a = ''`.\n\n## Putting the Content of a Register\n\nYou can use the `:put` command to paste the content of any one register. For example, if you run `:put a`, Vim will print the content of register a below the current line. This behaves much like `\"ap`, with the difference that the normal mode command `p` prints the register content after the cursor and the command `:put` prints the register content at newline.\n\nSince `:put` is a command-line command, you can pass it an address. `:10put a` will paste text from register a to below line 10.\n\nOne cool trick to pass `:put` with the black hole register (`\"_`). Since the black hole register does not store any text, `:put _` will insert a blank line instead. You can combine this with the global command to insert multiple blank lines. For example, to insert blank lines below all lines that contain the text \"end\", run `:g/end/put _`. You will learn about the global command later.\n\n## Learning Registers the Smart Way\n\nYou made it to the end. Congratulations! If you are feeling overwhelmed by the sheer information, you are not alone. When I first started learning about Vim registers, there was way too much information to take in at once.\n\nI don't think you should memorize all the registers immediately. To become productive, you can start by using only these 3 registers:\n1. The unnamed register (`\"\"`).\n2. The named registers (`\"a-z`).\n3. The numbered registers (`\"0-9`).\n\nSince the unnamed register defaults to `p` and `P`, you only have to learn two registers: the named registers and the numbered registers. Gradually learn more registers when you need them. Take your time.\n\nThe average human has a limited short-term memory capacity, about 5 - 7 items at once. That is why in my everyday editing, I only use about 5 -  7 named registers. There is no way I can remember all twenty-six in my head. I normally start with register a, then b, ascending the alphabetical order. Try it and experiment around to see what technique works best for you.\n\nVim registers are powerful. Used strategically, it can save you from typing countless repeating texts. Next, let's learn about macros.\n\n## Link\n- Prev [Ch07. The Dot Command](./ch07_the_dot_command.md)\n- Next [Ch09. Macros](./ch09_macros.md)\n"
  },
  {
    "path": "ch09_macros.md",
    "content": "# Ch09. Macros\n\nWhen editing files, you may find yourself repeating the same actions. Wouldn't it be nice if you could do those actions once and replay them whenever you need it? With Vim macros, you can record actions and store them inside Vim registers to be executed whenever you need it.\n\nIn this chapter, you will learn how to use macros to automate mundane tasks (plus it looks cool to watch your file edit itself).\n\n## Basic Macros\n\nHere is the basic syntax of a Vim macro:\n\n```\nqa                     Start recording a macro in register a\nq (while recording)    Stop recording macro\n```\n\nYou can choose any lowercase letters (a-z) to store macros. Here is how you can execute a macro:\n\n```\n@a    Execute macro from register a\n@@    Execute the last executed macros\n```\n\nSuppose you have this text and you want to uppercase everything on each line:\n\n```\nhello\nvim\nmacros\nare\nawesome\n```\n\nWith your cursor at the start of the line \"hello\", run:\n\n```\nqa0gU$jq\n```\n\nThe breakdown:\n- `qa` starts recording a macro in the a register.\n- `0` goes to beginning of the line.\n- `gU$` uppercases the text from your current location to the end of the line.\n- `j` goes down one line.\n- `q` stops recording.\n\nTo replay it, run `@a`. Just like many other Vim commands, you can pass a count argument to macros. For example, running `3@a` executes the macro three times.\n\n## Safety Guard\n\nMacro execution automatically ends when it encounters an error. Suppose you have this text:\n\n```\na. chocolate donut\nb. mochi donut\nc. powdered sugar donut\nd. plain donut\n```\n\nIf you want to uppercase the first word on each line, this macro should work:\n\n```\nqa0W~jq\n```\n\nHere's the breakdown of the command above:\n- `qa` starts recording a macro in the a register.\n- `0` goes to the beginning of the line.\n- `W` goes to the next WORD.\n- `~` toggles the case of the character under the cursor.\n- `j` goes down one line.\n- `q` stops recording.\n\nI prefer to overcount my macro execution than undercount it, so I usually call it ninety-nine times (`99@a`). With this command, Vim does not actually run this macro ninety-nine times. When Vim reaches the last line and runs `j` motion, it finds no more line to go down to, throws an error, and stops the macro execution.\n\nThe fact that macro execution stops upon the first error encounter is a good feature, otherwise Vim will continue to execute this macro ninety-nine times even though it already reaches the end of the line.\n\n## Command Line Macro\n\nRunning `@a` in normal mode is not the only way you can execute macros in Vim. You can also run `:normal @a` command line. `:normal` allows the user to execute any normal mode command passed as argument. In the case above, it is the same as running `@a` from normal mode.\n\nThe `:normal` command accepts range as arguments. You can use this to run macro in select ranges. If you want to execute your macro between lines 2 and 3, you can run `:2,3 normal @a`.\n\n## Executing a Macro Across Multiple Files\n\nSuppose you have multiple `.txt` files, each contains some texts. Your task is to uppercase the first word only on lines containing the word \"donut\". Assume you have `0W~j` in register a (the same macro as before). How can you quickly accomplish this?\n\nFirst file:\n\n```\n## savory.txt\na. cheddar jalapeno donut\nb. mac n cheese donut\nc. fried dumpling\n```\n\nSecond file:\n\n```\n## sweet.txt\na. chocolate donut\nb. chocolate pancake\nc. powdered sugar donut\n```\n\nThird file:\n\n```\n## plain.txt\na. wheat bread\nb. plain donut\n```\n\nHere is how you can do it:\n- `:args *.txt` to find all `.txt` files in your current directory.\n- `:argdo g/donut/normal @a` executes the global command `g/donut/normal @a` on each file inside `:args`.\n- `:argdo update` executes `update` command to save each file inside `:args` when the buffer has been modified.\n\nIf you are not familiar with the global command `:g/donut/normal @a`, it executes the command you give (`normal @a`) on lines that match the pattern (`/donut/`). I will go over the global command in a later chapter.\n\n## Recursive Macro\n\nYou can recursively execute a macro by calling the same macro register while recording that macro. Suppose you have this list again and you need to toggle the case of the first word:\n\n```\na. chocolate donut\nb. mochi donut\nc. powdered sugar donut\nd. plain donut\n```\n\nThis time, let's do it recursively. Run:\n\n```\nqaqqa0W~j@aq\n```\n\nHere is the breakdown of the steps:\n- `qaq` records an empty macro a. It is necessary to start with an empty register because when you recursively call the macro, it will run whatever is in that register.\n- `qa` starts recording on register a.\n- `0` goes to the first character in the current line.\n- `W` goes to the next WORD.\n- `~` toggles the case of the character under the cursor.\n- `j` goes down one line.\n- `@a` executes macro a.\n- `q` stops recording.\n\nNow you can just run `@a` and watch Vim execute the macro recursively.\n\nHow did the macro know when to stop? When the macro was on the last line, it tried to run `j`, since there was no more line to go to, it stopped the macro execution.\n\n## Appending a Macro\n\nIf you need to add actions to an existing macro, instead of recreating the macro from scratch, you can append actions to an existing one. In the register chapter, you learned that you can append a named register by using its uppercased symbol. The same rule applies. To append actions to register a macro, use register A.\n\nRecord a macro in register a: `qa0W~q` (this sequence toggles the case of the next WORD in a line). If you want to append a new sequence to also add a dot at the end of the line, run:\n\n```\nqAA.<Esc>q\n```\n\nThe breakdown:\n- `qA` starts recording the macro in register A.\n- `A.<Esc>` inserts at the end of the line (here `A` is the insert mode command, not to be confused with the macro A) a dot, then exits insert mode.\n- `q` stops recording macro.\n\nNow when you execute `@a`, it not only toggles the case of the next WORD, it also adds a dot at the end of the line.\n\n## Amending a Macro\n\nWhat if you need to add new actions in the middle of a macro?\n\nAssume that you have a macro that toggles the first actual word and adds a period at the end of the line, `0W~A.<Esc>` in register a. Suppose that between uppercasing the first word and adding a period at the end of the line, you need to add the word \"deep fried\" right before the word \"donut\" *(because the only thing better than regular donuts are deep fried donuts)*.\n\nI will reuse the text from earlier section:\n```\na. chocolate donut\nb. mochi donut\nc. powdered sugar donut\nd. plain donut\n```\n\nFirst, let's call the existing macro (assume you have kept the macro from the previous section in register a) with `:put a`:\n\n```\n0W~A.^[\n```\n\nWhat is this `^[`? Didn't you do `0W~A.<Esc>`? Where is the `<Esc>`? `^[` is Vim's *internal code* representation of `<Esc>`. With certain special keys, Vim prints the representation of those keys in the form of internal codes. Some common keys that have internal code representations are `<Esc>`, `<Backspace>`, and `<Enter>`. There are more special keys, but they are not within the scope of this chapter.\n\nBack to the macro, right after the toggle case operator (`~`), let's add the instructions to go to the end of the line (`$`), go back one word (`b`), go to the insert mode (`i`), type \"deep fried \" (don't forget the space after \"fried \"), and exit insert mode (`<Esc>`).\n\nHere is what you will end up with:\n\n```\n0W~$bideep fried <Esc>A.^[\n```\n\nThere is a small problem. Vim does not understand `<Esc>`. You can't literally type `<Esc>`. You will have to write the internal code representation for the `<Esc>` key. While in insert mode, you press `Ctrl-V` followed by `<Esc>`. Vim will print `^[`.` Ctrl-V` is an insert mode operator to insert the next non-digit character *literally*. Your macro code should look like this now:\n\n```\n0W~$bideep fried ^[A.^[\n```\n\nTo add the amended instruction into register a, you can do it the same way as adding a new entry into a named register. At the start of the line, run `\"ay$` to store the yanked text in register a.\n\nNow when you execute `@a`, your macro will toggle the case of the first word, add \"deep fried \" before \"donut\", and add a \".\" at the end of the line. Yum!\n\nAn alternative way to amend a macro is to use a command line expression. Do `:let @a=\"`, then do `Ctrl-R a`, this will literally paste the content of register a. Finally, don't forget to close the double quotes (`\"`). You might have something like `:let @a=\"0W~$bideep fried ^[A.^[\"`.\n\n## Macro Redundancy\n\nYou can easily duplicate macros from one register to another. For example, to duplicate a macro in register a to register z, you can do `:let @z = @a`. `@a` represents the content of register a. Now if you run `@z`, it does the exact same actions as `@a`.\n\nI find creating a redundancy useful on my most frequently used macros. In my workflow, I usually record macros in the first seven alphabetical letters (a-g) and I often replace them without much thought. If I move the useful macros towards the end of the alphabets, I can preserve them without worrying that I might accidentally replace them.\n\n## Series vs Parallel Macro\n\nVim can execute macros in series and parallel. Suppose you have this text:\n\n```\nimport { FUNC1 } from \"library1\";\nimport { FUNC2 } from \"library2\";\nimport { FUNC3 } from \"library3\";\nimport { FUNC4 } from \"library4\";\nimport { FUNC5 } from \"library5\";\n```\n\nIf you want to record a macro to lowercase all the uppercased \"FUNC\", this macro should work:\n\n```\nqa0f{gui{jq\n```\n\nThe breakdown:\n- `qa` starts recording in register a.\n- `0` goes to first line.\n- `f{` finds the first instance of \"{\".\n- `gui{` lowercases (`gu`) the text inside the bracket text-object (`i{`).\n- `j` goes down one line.\n- `q` stops macro recording.\n\nNow you can run `99@a` to execute it on the remaining lines. However, what if you have this import expression inside your file?\n\n```\nimport { FUNC1 } from \"library1\";\nimport { FUNC2 } from \"library2\";\nimport { FUNC3 } from \"library3\";\nimport foo from \"bar\";\nimport { FUNC4 } from \"library4\";\nimport { FUNC5 } from \"library5\";\n```\n\nRunning `99@a`, only executes the macro three times. It does not execute the macro on last two lines because the execution fails to run `f{` on the \"foo\" line. This is expected when running the macro in series. You can always go to the next line where \"FUNC4\" is and replay that macro again. But what if you want to get everything done in one go?\n\nRun the macro in parallel.\n\nRecall from earlier section that macros can be executed using the  command line command `:normal` (ex: `:3,5 normal @a` executes macro a on lines 3-5). If you run `:1,$ normal @a`, you will see that the macro is being executed on all lines except the \"foo\" line. It works!\n\nAlthough internally Vim does not actually run the macros in parallel, outwardly, it behaves like it. Vim executes `@a` *independently* on each line from the first to the last line (`1,$`). Since Vim executes these macros independently, each line does not know that one of the macro executions had failed on the \"foo\" line.\n\n## Learn Macros the Smart Way\n\nMany things you do in editing are repetitive. To get better at editing, get into the habit of detecting repetitive actions. Use macros (or dot command) so you don't have to perform the same action twice. Almost everything that you can do in Vim can be replicated with macros.\n\nIn the beginning, I find it very awkward to write macros, but don't give up. With enough practice, you will get into the habit of automating everything.\n\nYou might find it helpful to use mnemonics to help remember your macros. If you have a macro that creates a function, use the \"f register (`qf`). If you have a macro for numerical operations, the \"n register should work (`qn`). Name it with the *first named register* that comes to your mind when you think of that operation. I also find that the \"q register makes a good default macro register because `qq` requires less brain power to come up with. Lastly, I also like to increment my macros in alphabetical orders, like `qa`, then `qb`, then `qc`, and so on.\n\nFind a method that works best for you.\n\n## Link\n- Prev [Ch08. Registers](./ch08_registers.md)\n- Next [Ch10. Undo](./ch10_undo.md)\n"
  },
  {
    "path": "ch10_undo.md",
    "content": "# Ch10. Undo\n\nWe all make all sorts of typing mistakes. That's why undo is an essential feature in any modern software. Vim's undo system is not only capable of undoing and redoing simple mistakes, but also accessing different text states, giving you control over all the texts you have ever typed. In this chapter, you will learn how to undo, redo, navigate an undo branch, persist undo, and travel across time.\n\n## Undo, Redo, and UNDO\n\nTo perform a basic undo, you can use `u` or run `:undo`.\n\nIf you have this text (note the empty line below \"one\"):\n\n```\none\n\n```\n\nThen you add another text:\n\n```\none\ntwo\n```\n\nIf you press `u`, Vim undoes the text \"two\".\n\nHow does Vim know how much to undo? Vim undoes a single \"change\" at a time, similar to a dot command's change (unlike the dot command, command-line command also count as a change).\n\nTo redo the last change, press `Ctrl-R` or run `:redo`. After you undo the text above to remove \"two\", running `Ctrl-R` will get the removed text back.\n\nVim also has UNDO that you can run with `U`. It undoes all latest changes.\n\nHow is `U` different from `u`? First, `U` removes *all* the changes on the latest changed line, while `u` only removes one change at a time. Second, while doing `u` does not count as a change, doing `U` counts as a change.\n\nBack to this example:\n\n```\none\ntwo\n```\n\nChange the second line to \"three\":\n\n```\none\nthree\n```\n\nChange the second line again and replace it with \"four\":\n\n```\none\nfour\n```\n\nIf you press `u`, you will see \"three\". If you press  `u` again, you'll see \"two\". If instead of pressing `u` when you still had the text \"four\", you had pressed `U`, you will see:\n\n```\none\n\n```\n\n`U` bypasses all the intermediary changes and goes to the original state when you started (an empty line). In addition, since UNDO actually creates a new change in Vim, you can UNDO your UNDO. `U` followed by `U` will undo itself. You can press `U`, then `U`, then `U`, etc. You will see the same two text states toggling back and forth.\n\nI personally do not use `U` because it is hard to remember the original state (I seldom ever need it).\n\nVim sets a maximum number of how many times you can undo in `undolevels` option variable. You can check it with `:echo &undolevels`. I have mine set to be 1000. To change yours to 1000, run `:set undolevels=1000`. Feel free to set it to any number you like.\n\n## Breaking the Blocks\n\nI mentioned earlier that `u` undoes a single \"change\" similar to the dot command's change: the texts inserted from when you enter the insert mode until you exit it count as a change.\n\nIf you do `ione two three<Esc>` then press `u`, Vim removes the entire \"one two three\" text because the whole thing counts as a change. This is not a big deal if you have written short texts, but what if you have written several paragraphs within one insert mode session without exiting and later you realized you made a mistake? If you press `u`, everything you had written would be removed. Wouldn't it be useful if you can press `u` to remove only a section of your text?\n\nLuckily, you can break the undo blocks. When you are typing in insert mode, pressing `Ctrl-G u` creates an undo breakpoint. For example, if you do `ione <Ctrl-G u>two <Ctrl-G u>three<Esc>`, then press `u`, you will only lose the text \"three\" (press `u` one more time to remove \"two\"). When you write a long text, use `Ctrl-G u` strategically. The end of each sentence, between two paragraphs, or after each line of code are prime locations to add undo breakpoints to make it easier to undo your mistakes if you ever make one.\n\nIt is also useful to create an undo breakpoint when deleting chunks in insert mode with `Ctrl-W` (delete the word before the cursor) and `Ctrl-U` (delete all text before the cursor). A friend suggested to use the following maps:\n\n```\ninoremap <c-u> <c-g>u<c-u>\ninoremap <c-w> <c-g>u<c-w>\n```\n\nWith these, you can easily recover the deleted texts.\n\n## Undo Tree\n\nVim stores every change ever written in an undo tree. Start a new empty file. Then add a new text:\n\n```\none\n\n```\n\nAdd a new text:\n\n```\none\ntwo\n```\n\nUndo once:\n\n```\none\n\n```\n\nAdd a different text:\n\n```\none\nthree\n```\n\nUndo again:\n\n```\none\n\n```\n\nAnd add another different text:\n\n```\none\nfour\n```\n\n\nNow if you undo, you will lose the text \"four\" you just added:\n\n```\none\n\n```\n\nIf you undo one more time:\n\n```\n\n```\n\nYou will lose the text \"one\". In most text editor, getting the texts \"two\" and \"three\" back would have been impossible, but not with Vim! Press `g+` and you'll get your text \"one\" back:\n\n```\none\n\n```\n\nType `g+` again and you will see an old friend:\n\n```\none\ntwo\n```\n\nLet's keep going. Press `g+` again:\n\n```\none\nthree\n```\n\nPress `g+` one more time:\n\n```\none\nfour\n```\n\nIn Vim, every time you press `u` and then make a different change, Vim stores the previous state's text by creating an \"undo branch\". In this example, after you typed \"two\", then pressed `u`, then typed \"three\", you created a leaf branch that stores the state containing the text \"two\". At that moment, the undo tree contained at least two leaf nodes: the main node containing the text \"three\" (most recent) and the undo branch node containing the text \"two\". If you had done another undo and typed the text \"four\", you would have at least three nodes: a main node containing the text \"four\" and two nodes containing the texts \"three\" and \"two\".\n\nTo traverse each undo tree nodes, you can use `g+` to go to a newer state and `g-` to go to an older state. The difference between `u`, `Ctrl-R`, `g+`, and `g-` is that both `u` and `Ctrl-R` traverse only the *main* nodes in undo tree while `g+` and `g-` traverse *all* nodes in the undo tree.\n\nUndo tree is not easy to visualize. I find [vim-mundo](https://github.com/simnalamburt/vim-mundo) plugin to be very useful to help visualize Vim's undo tree. Give it some time to play around with it.\n\n## Persistent Undo\n\nIf you start Vim, open a file, and immediately press `u`, Vim will probably display \"*Already at oldest change*\" warning. There is nothing to undo because you haven't made any changes. \n\nTo rollover the undo history from the last editing session, Vim can preserve your undo history with an undo file with `:wundo`.\n\nCreate a file `mynumbers.txt`. Type:\n\n```\none\n```\n\nThen type another line (make sure each line counts as a change):\n\n```\none\ntwo\n```\n\nType another line:\n\n```\none\ntwo\nthree\n```\n\nNow create your undo file with `:wundo {my-undo-file}`. If you need to overwrite an existing undo file, you can add `!` after `wundo`.\n\n```\n:wundo! mynumbers.undo\n```\n\nThen exit Vim.\n\nBy now you should have `mynumbers.txt` and `mynumbers.undo` files in your directory. Open up `mynumbers.txt` again and try pressing `u`. You can't. You haven't made any changes since you opened the file. Now load your undo history by reading the undo file with `:rundo`:\n\n```\n:rundo mynumbers.undo\n```\n\nNow if you press `u`, Vim removes \"three\". Press `u` again to remove \"two\". It is like you never even closed Vim!\n\nIf you want to have an automatic undo persistence, one way to do it is by adding these in vimrc:\n\n```\nset undodir=~/.vim/undo_dir\nset undofile\n```\n\nThe setting above will put all the undofile in one centralized directory, the `~/.vim` directory. The name `undo_dir` is arbitrary. `set undofile` tells Vim to turn on `undofile` feature because it is off by default. Now whenever you save, Vim automatically creates and updates the relevant file inside the `undo_dir` directory (make sure that you create the actual `undo_dir` directory inside `~/.vim` directory before running this).\n\n## Time Travel\n\nWho says that time travel doesn't exist? Vim can travel to a text state in the past with `:earlier` command-line command.\n\nIf you have this text:\n\n```\none\n\n```\nThen later you add:\n\n```\none\ntwo\n```\n\nIf you had typed \"two\" less than ten seconds ago, you can go back to the state where \"two\" didn't exist ten seconds ago with:\n\n```\n:earlier 10s\n```\n\nYou can use `:undolist` to see when the last change was made. `:earlier` also accepts different arguments:\n\n```\n:earlier 10s    Go to the state 10 seconds before\n:earlier 10m    Go to the state 10 minutes before\n:earlier 10h    Go to the state 10 hours before\n:earlier 10d    Go to the state 10 days before\n```\n\nIn addition, it also accepts a regular `count` as argument to tell Vim to go to the older state `count` times. For example, if you do `:earlier 2`, Vim will go back to an older text state two changes ago. It is the same as doing `g-` twice. You can also tell it to go to the older text state 10 saves ago with `:earlier 10f`.\n\nThe same set of arguments work with `:earlier` counterpart: `:later`.\n\n```\n:later 10s    go to the state 10 seconds later\n:later 10m    go to the state 10 minutes later\n:later 10h    go to the state 10 hours later\n:later 10d    go to the state 10 days later\n:later 10     go to the newer state 10 times\n:later 10f    go to the state 10 saves later\n```\n\n## Learn Undo the Smart Way\n\n`u` and `Ctrl-R` are two indispensable Vim commands for correcting mistakes. Learn them first. Next, learn how to use `:earlier` and `:later` using the time arguments first. After that, take your time to understand the undo tree. The [vim-mundo](https://github.com/simnalamburt/vim-mundo) plugin helped me a lot. Type along the texts in this chapter and check the undo tree as you make each change. Once you grasp it, you will never see the undo system the same way again.\n\nPrior to this chapter, you learned how to find any text in a project space, with undo, you can now find any text in a time dimension. You are now able to search for any text by its location and time written. You have achieved Vim-omnipresence.\n\n\n## Link\n- Prev [Ch09. Macros](./ch09_macros.md)\n- Next [Ch11. Visual Mode](./ch11_visual_mode.md)\n"
  },
  {
    "path": "ch11_visual_mode.md",
    "content": "# Ch11. Visual Mode\n\nHighlighting and applying changes to a body of text is a common feature in many text editors and word processors. Vim can do this using visual mode. In this chapter, you will learn how to use the visual mode to manipulate texts efficiently.\n\n## The Three Types of Visual Modes\n\nVim has three different visual modes. They are:\n\n```\nv         Character-wise visual mode\nV         Line-wise visual mode\nCtrl-V    Block-wise visual mode\n```\n\nIf you have the text:\n\n```\none\ntwo\nthree\n```\n\nCharacter-wise visual mode works with individual characters. Press `v` on the first character. Then go down to the next line with `j`. It highlights all texts from \"one\" up to your cursor location. If you press `gU`, Vim uppercases the highlighted characters.\n\nLine-wise visual mode works with lines. Press `V` and watch Vim selects the entire line your cursor is on. Just like character-wise visual mode, if you run `gU`, Vim uppercases the highlighted characters.\n\nBlock-wise visual mode works with rows and columns. It gives you more freedom of movement than the other two modes. If you press `Ctrl-V`, Vim highlights the character under the cursor just like character-wise visual mode, except instead of highlighting each character until the end of the line before going down to the next line, it goes to the next line with minimal highlighting. Try moving around with `h/j/k/l` and watch the cursor move.\n\nOn the bottom left of your Vim window, you will see either `-- VISUAL --`, `-- VISUAL LINE --`, or `-- VISUAL BLOCK --` displayed to indicate which visual mode you are in.\n\nWhile you are inside a visual mode, you can switch to another visual mode by pressing either `v`, `V`, or `Ctrl-V`. For example, if you are in line-wise visual mode and you want to switch to block-wise visual mode, run `Ctrl-V`. Try it!\n\nThere are three ways to exit the visual mode: `<Esc>`, `Ctrl-C`, and the same key as your current visual mode. What the latter means is if you are currently in the line-wise visual mode (`V`), you can exit it by pressing `V` again. If you are in the character-wise visual mode, you can exit it by pressing `v`.\n\nThere is actually one more way to enter the visual mode:\n\n```\ngv    Go to the previous visual mode\n```\n\nIt will start the same visual mode on the same highlighted text block as you did last time.\n\n## Visual Mode Navigation\n\nWhile in a visual mode, you can expand the highlighted text block with Vim motions.\n\nLet's use the same text you used earlier:\n\n```\none\ntwo\nthree\n```\n\nThis time let's start from the line \"two\". Press `v` to go to the character-wise visual mode (here the square brackets `[]` represent the character highlights):\n\n```\none\n[t]wo\nthree\n```\n\nPress `j` and Vim will highlight all the text from the line \"two\" down to the first character of the line \"three\".\n\n```\none\n[two\nt]hree\n```\n\nAssume from this position, you want to add the line \"one\" too. If you press `k`, to your dismay, the highlight moves away from the line \"three\". \n\n```\none\n[t]wo\nthree\n```\n\nIs there a way to freely expand visual selection to move in any direction you want? Definitely. Let's back up a little bit to where you have the line \"two\" and \"three\" highlighted.\n\n```\none\n[two\nt]hree    <-- cursor\n```\n\nVisual highlight follows the cursor movement. If you want to expand it upward to the line \"one\", you need to move the cursor up to the line \"two\". Right now the cursor is on the line \"three\". You can toggle the cursor location with either `o` or `O`.\n\n```\none\n[two     <-- cursor\nt]hree\n```\n\nNow when you press `k`, it no longer reduces the selection, but expands it upward.\n\n```\n[one\ntwo\nt]hree\n```\n\nWith `o` or `O` in visual mode, the cursor jumps from the beginning to the end of the highlighted block, allowing you to expand the highlight area.\n\n## Visual Mode Grammar\n\nThe visual mode shares many operations with normal mode.\n\nFor example, if you have the following text and you want to delete the first two lines from visual mode:\n\n```\none\ntwo\nthree\n```\n\nHighlight the lines \"one\" and \"two\" with the line-wise visual mode (`V`):\n\n```\n[one\ntwo]\nthree\n```\n\nPressing `d` will delete the selection, similar to normal mode. Notice the grammar rule from normal mode, verb + noun, does not apply. The same verb is still there (`d`), but there is no noun in visual mode. The grammar rule in visual mode is noun + verb, where noun is the highlighted text. Select the text block first, then the command follows.\n\nIn normal mode, there are some commands that do not require a motion, like `x` to delete a single character under the cursor and `r` to replace the character under the cursor (`rx` replaces the character under the cursor with \"x\"). In visual mode, these commands are now being applied to the entire highlighted text instead of a single character. Back at the highlighted text:\n\n```\n[one\ntwo]\nthree\n```\n\nRunning `x` deletes all highlighted texts.\n\nYou can use this behavior to quickly create a header in markdown text. Suppose you need to quickly turn the following text into a first-level markdown header (\"===\"):\n\n```\nChapter One\n```\n\nFirst, copy the text with `yy`, then paste it with `p`:\n\n```\nChapter One\nChapter One\n```\n\nNow, go to the second line and select it with line-wise visual mode:\n\n```\nChapter One\n[Chapter One]\n```\n\nA first-level header is a series of \"=\" below a text. Run `r=`, voila! This saves you from typing \"=\" manually.\n\n```\nChapter One\n===========\n```\n\nTo learn more about operators in visual mode, check out `:h visual-operators`.\n\n## Visual Mode and Command-line Commands\n\nYou can selectively apply command-line commands on a highlighted text block. If you have these statements and you want to substitute \"const\" with \"let\" only on the first two lines:\n\n```\nconst one = \"one\";\nconst two = \"two\";\nconst three = \"three\";\n```\n\nHighlight the first two lines with *any* visual mode and run the substitute command `:s/const/let/g`:\n\n```\nlet one = \"one\";\nlet two = \"two\";\nconst three = \"three\";\n```\n\nNotice I said you can do this with *any* visual mode. You do not have to highlight the entire line to run the command on that line. As long as you select at least a character on each line, the command is applied.\n\n## Adding Text on Multiple Lines\n\nYou can add text on multiple lines in Vim using the block-wise visual mode. If you need to add a semicolon at the end of each line:\n\n```\nconst one = \"one\"\nconst two = \"two\"\nconst three = \"three\"\n```\n\nWith your cursor on the first line:\n- Run block-wise visual mode and go down two lines (`Ctrl-V jj`).\n- Highlight to the end of the line (`$`).\n- Append (`A`) then type \";\".\n- Exit visual mode (`<Esc>`).\n\nYou should see the appended \";\" on each line now. Pretty cool! There are two ways to enter the insert mode from block-wise visual mode: `A` to enter the text after the cursor or `I` to enter the text before the cursor. Do not confuse them with `A` (append text at the end of the line) and `I` (insert text before the first non-blank line) from normal mode.\n\nAlternatively, you can also use the `:normal` command to add text on multiple lines:\n- Highlight all 3 lines (`vjj`).\n- Type `:normal! A;`.\n\nRemember, `:normal` command executes normal mode commands. You can instruct it to run `A;` to append text \";\" at the end of the line.\n\n## Incrementing Numbers\n\nVim has `Ctrl-X` and `Ctrl-A` commands to decrement and increment numbers. When used with visual mode, you can increment numbers across multiple lines.\n\nIf you have these HTML elements:\n\n```\n<div id=\"app-1\"></div>\n<div id=\"app-1\"></div>\n<div id=\"app-1\"></div>\n<div id=\"app-1\"></div>\n<div id=\"app-1\"></div>\n```\n\nIt is a bad practice to have several ids having the same name, so let's increment them to make them unique:\n- Move your cursor to the \"1\" on the second line.\n- Start block-wise visual mode and go down 3 lines (`Ctrl-V 3j`). This highlights the remaining  \"1\"s. Now all \"1\" should be highlighted (except the first line).\n- Run `g Ctrl-A`.\n\nYou should see this result:\n\n```\n<div id=\"app-1\"></div>\n<div id=\"app-2\"></div>\n<div id=\"app-3\"></div>\n<div id=\"app-4\"></div>\n<div id=\"app-5\"></div>\n```\n\n`g Ctrl-A` increments numbers on multiple lines. `Ctrl-X/Ctrl-A` can increment letters too, with the number formats option:\n\n```\nset nrformats+=alpha\n```\n\nThe `nrformats` option instructs Vim which bases are considered as \"numbers\" for `Ctrl-A` and `Ctrl-X` to increment and decrement. By adding `alpha`, an alphabetical character is now considered as a number. If you have the following HTML elements:\n\n```\n<div id=\"app-a\"></div>\n<div id=\"app-a\"></div>\n<div id=\"app-a\"></div>\n<div id=\"app-a\"></div>\n<div id=\"app-a\"></div>\n```\n\nPut your cursor on the second \"app-a\". Use the same technique as above (`Ctrl-V 3j` then `g Ctrl-A`) to increment the ids.\n\n```\n<div id=\"app-a\"></div>\n<div id=\"app-b\"></div>\n<div id=\"app-c\"></div>\n<div id=\"app-d\"></div>\n<div id=\"app-e\"></div>\n```\n\n## Selecting the Last Visual Mode Area\n\nEarlier in this chapter, I mentioned that `gv` can quickly highlight the last visual mode highlight. You can also go to the location of the start and the end of the last visual mode with these two special marks:\n\n```\n`<    Go to the first place of the previous visual mode highlight\n`>    Go to the last place of the previous visual mode highlight\n```\n\nEarlier, I also mentioned that you can selectively execute command-line commands on a highlighted text, like `:s/const/let/g`. When you did that, you'd see this below:\n\n```\n:`<,`>s/const/let/g\n```\n\nYou were actually executing a *ranged* `s/const/let/g` command (with the two marks as the addresses). Interesting!\n\nYou can always edit these marks anytime you wish. If instead you needed to substitute from the start of the highlighted text to the end of the file, you just change the command to:\n\n```\n:`<,$s/const/let/g\n```\n\n## Entering Visual Mode From Insert Mode\n\nYou can also enter visual mode from the insert mode. To go to character-wise visual mode while you are in insert mode:\n\n```\nCtrl-O v\n```\n\nRecall that running `Ctrl-O` while in the insert mode lets you execute a normal mode command. While in this normal-mode-command-pending mode, run `v` to enter character-wise visual mode. Notice that on the bottom left of the screen, it says `--(insert) VISUAL--`. This trick works with any visual mode operator: `v`, `V`, and `Ctrl-V`.\n\n## Select Mode\n\nVim has a mode similar to visual mode called the select mode. Like the visual mode, it also has three different modes:\n\n```\ngh         Character-wise select mode\ngH         Line-wise select mode\ngCtrl-h    Block-wise select mode\n```\n\nSelect mode emulates a regular editor's text highlighting behavior closer than Vim's visual mode does.\n\nIn a regular editor, after you highlight a text block and type a letter, say the letter \"y\", it will delete the highlighted text and insert the letter \"y\". If you highlight a line with line-wise select mode (`gH`) and type \"y\", it will delete the highlighted text and insert the letter \"y\".\n\nContrast this select mode with visual mode: if you highlight a line of text with line-wise visual mode (`V`) and type \"y\", the highlighted text will not be deleted and replaced by the literal letter \"y\", it will be yanked. You can't execute normal mode commands on highlighted text in select mode.\n\nI personally never used select mode, but it's good to know that it exists.\n\n## Learn Visual Mode the Smart Way\n\nThe visual mode is Vim's representation of the text highlighting procedure.\n\nIf you find yourself using visual mode operation far more often than normal mode operations, be careful. This is an anti-pattern. It takes more keystrokes to run a visual mode operation than its normal mode counterpart. For example, if you need to delete an inner word, why use four keystrokes, `viwd` (visually highlight an inner word then delete), if you can accomplish it with just three keystrokes (`diw`)? The latter is more direct and concise. Of course, there will be times when visual modes are appropriate, but in general, favor a more direct approach.\n\n## Link\n- Prev [Ch10. Undo](./ch10_undo.md)\n- Next [Ch12. Search and Substitute](./ch12_search_and_substitute.md)\n"
  },
  {
    "path": "ch12_search_and_substitute.md",
    "content": "# Ch12. Search and Substitute\n\nThis chapter covers two separate but related concepts: search and substitute. Often when editing, you need to search multiple texts based on their least common denominator patterns. By learning how to use regular expressions in search and substitute instead of literal strings, you will be able to target any text quickly.\n\nAs a side note, in this chapter, I will use `/` when talking about search. Everything you can do with `/` can also be done with `?`.\n\n## Smart Case Sensitivity\n\nIt can be tricky trying to match the case of the search term. If you are searching for the text \"Learn Vim\", you can easily mistype the case of one letter and get a false search result. Wouldn't it be easier and safer if you could match any case? This is where the option `ignorecase` shines. Just add `set ignorecase` in your vimrc and all your search terms become case insensitive. Now you don't have to do `/Learn Vim` anymore, `/learn vim` will work.\n\nHowever, there are times when you need to search for a case specific phrase. One way to do that is to turn off `ignorecase` option by running `set noignorecase`, but that is a lot of work to turn on and off each time you need to search for a case sensitive phrase.\n\nTo avoid toggling `ignorecase`, Vim has a `smartcase` option to search for case insensitive string if the search pattern *contains at least one uppercase character*. You can combine both `ignorecase` and `smartcase` to perform a case insensitive search when you enter all lowercase characters and a case sensitive search when you enter one or more uppercase characters.\n\nInside your vimrc, add:\n\n```\nset ignorecase smartcase\n```\n\nIf you have these texts:\n\n```\nhello\nHELLO\nHello\n```\n\n- `/hello` matches \"hello\", \"HELLO\", and \"Hello\".\n- `/HELLO` matches only \"HELLO\".\n- `/Hello` matches only \"Hello\".\n\nThere is one downside. What if you need to search for only a lowercase string? When you do `/hello`, Vim now does case insensitive search. You can use `\\C` pattern anywhere in your search term to tell Vim that the subsequent search term will be case sensitive. If you do `/\\Chello`, it will strictly match \"hello\", not \"HELLO\" or \"Hello\".\n\n## First and Last Character in a Line\n\nYou can use `^` to match the first character in a line and `$` to match the last character in a line.\n\nIf you have this text:\n\n```\nhello hello\n```\n\nYou can target the first \"hello\" with `/^hello`. The character that follows `^` must be the first character in a line. To target the last \"hello\", run `/hello$`. The character before `$` must be the last character in a line.\n\nIf you have this text:\n\n```\nhello hello friend\n```\n\nRunning `/hello$` will not match anything because \"friend\" is the last term in that line, not \"hello\".\n\n## Repeating Search\n\nYou can repeat the previous search with `//`. If you have just searched for `/hello`, running `//` is equivalent to running `/hello`. This shortcut can save you some keystrokes especially if you just searched for a long string. Also recall that you can use `n` and `N` to repeat the last search with the same direction and opposite direction, respectively.\n\nWhat if you want to quickly recall *n* last search term? You can quickly traverse the search history by first pressing `/`, then press `up`/`down` arrow keys (or `Ctrl-N`/`Ctrl-P`) until you find the search term you need. To see all your search history, you can run `:history /`.\n\nWhen you reach the end of a file while searching, Vim throws an error: `\"Search hit the BOTTOM without match for: {your-search}\"`. Sometimes this can be a good safeguard from oversearching, but other times you want to cycle the search back to the top again. You can use the `set wrapscan` option to make Vim search back at the top of the file when you reach the end of the file. To turn this feature off, do `set nowrapscan`.\n\n## Searching for Alternative Words\n\nIt is common to search for multiple words at once. If you need to search for *either* \"hello vim\" or \"hola vim\", but not \"salve vim\" or \"bonjour vim\", you can use the `|` pattern.\n\nGiven this text:\n\n```\nhello vim\nhola vim\nsalve vim\nbonjour vim\n```\n\nTo match both \"hello\" and  \"hola\", you can do `/hello\\|hola`. You have to escape (`\\`) the or (`|`) operator, otherwise Vim will literally search for the string \"|\".\n\nIf you don't want to type `\\|` every time, you can use the `magic` syntax (`\\v`) at the start of the search: `/\\vhello|hola`. I will not cover `magic` in this guide, but with `\\v`, you don't have to escape special characters anymore. To learn more about `\\v`, feel free to check out `:h \\v`.\n\n## Setting the Start and End of a Match\n\nMaybe you need to search for a text that is a part of a compound word. If you have these texts:\n\n```\n11vim22\nvim22\n11vim\nvim\n```\n\nIf you need to select \"vim\" but only when it starts with \"11\" and ends with \"22\", you can use `\\zs` (starting match) and `\\ze` (ending match) operators. Run:\n\n```\n/11\\zsvim\\ze22\n```\n\nVim still has to match the entire pattern \"11vim22\", but only highlights the pattern sandwiched between `\\zs` and `\\ze`. Another example:\n\n```\nfoobar\nfoobaz\n```\n\nIf you need to match the \"foo\" in \"foobaz\" but not in \"foobar\", run:\n\n```\n/foo\\zebaz\n```\n\n## Searching Character Ranges\n\nAll your search terms up to this point have been a literal word search. In real life, you may have to use a general pattern to find your text. The most basic pattern is the character range, `[ ]`.\n\nIf you need to search for any digit, you probably don't want to type `/0\\|1\\|2\\|3\\|4\\|5\\|6\\|7\\|8\\|9\\|0` every single time. Instead, use `/[0-9]` to match for a single digit. The `0-9` expression represents a range of numbers 0-9 that Vim will try to match, so if you are looking for digits between 1 to 5 instead, use `/[1-5]`.\n\nDigits are not the only data types Vim can look up. You can also do `/[a-z]` to search for lowercase alphas and `/[A-Z]` to search for uppercase alphas.\n\nYou can combine these ranges together. If you need to search for digits 0-9 and both lowercase and uppercase alphas from \"a\" to \"f\" (like a hex), you can do `/[0-9a-fA-F]`.\n\nTo do a negative search, you can add `^` inside the character range brackets. To search for a non-digit, run `/[^0-9]`. Vim will match any character as long as it is not a digit. Beware that the caret (`^`) inside the range brackets is different from the beginning-of-a-line caret (ex: `/^hello`). If a caret is outside of a pair of brackets and is the first character in the search term, it means \"the first character in a line\". If a caret is inside a pair of brackets and it is the first character inside the brackets, it means a negative search operator. `/^abc` matches the first \"abc\" in a line and `/[^abc]` matches any character except for an \"a\", \"b\", or \"c\".\n\n## Searching for Repeating Characters\n\nIf you need to search for double digits in this text:\n\n```\n1aa\n11a\n111\n```\n\nYou can use `/[0-9][0-9]` to match a two-digit character, but this method is unscalable. What if you need to match twenty digits? Typing `[0-9]` twenty times is not a fun experience. That's why you need a `count` argument.\n\nYou can pass `count` to your search. It has the following syntax:\n\n```\n{n,m}\n```\n\nBy the way, these `count` braces need to be escaped when you use them in Vim. The `count` operator is placed after a single character you want to increment.\n\nHere are the four different variations of the `count` syntax:\n- `{n}` is an exact match. `/[0-9]\\{2\\}`  matches the two digit numbers: \"11\" and the \"11\" in \"111\".\n- `{n,m}` is a range match. `/[0-9]\\{2,3\\}` matches between 2 and 3 digit numbers: \"11\"  and \"111\".\n- `{,m}` is an up-to match. `/[0-9]\\{,3\\}` matches up to 3 digit numbers: \"1\", \"11\", and \"111\".\n- `{n,}` is an at-least match. `/[0-9]\\{2,\\}` matches at least a 2 or more digit numbers: \"11\" and \"111\".\n\nThe count arguments `\\{0,\\}` (zero or more) and `\\{1,\\}` (one or more) are common search patterns and Vim has special operators for them: `*` and `+` (`+` needs to be escaped while `*` works fine without the escape). If you do `/[0-9]*`, it is the same as `/[0-9]\\{0,\\}`. It searches for zero or more digits. It will match \"\", \"1\", \"123\". By the way, it will also match non-digits like \"a\", because there is technically zero digit in the letter \"a\". Think carefully before using `*`. If you do `/[0-9]\\+`, it is the same as `/[0-9]\\{1,\\}`. It searches for one or more digits. It will match \"1\" and \"12\".\n\n## Predefined Character Ranges\n\nVim has predefined ranges for common characters like digits and alphas. I will not go through every single one here, but you can find the full list inside `:h /character-classes`. Here are the useful ones:\n\n```\n\\d    Digit [0-9]\n\\D    Non-digit [^0-9]\n\\s    Whitespace character (space and tab)\n\\S    Non-whitespace character (everything except space and tab)\n\\w    Word character [0-9A-Za-z_]\n\\l    Lowercase alphas [a-z]\n\\u    Uppercase character [A-Z]\n```\n\nYou can use them like you would use character ranges. To search for any single digit, instead of using `/[0-9]`, you can use `/\\d` for a more concise syntax.\n\n## Search Example: Capturing a Text Between a Pair of Similar Characters\n\nIf you want to search for a phrase surrounded by a pair of double quotes:\n\n```\n\"Vim is awesome!\"\n```\n\nRun this:\n\n```\n/\"[^\"]\\+\"\n```\n\nLet's break it down:\n- `\"` is a literal double quote. It matches the first double quote.\n- `[^\"]` means any character except for a double quote. It matches any alphanumeric and whitespace character as long as it is not a double quote.\n- `\\+` means one or more. Since it is preceded by `[^\"]`, Vim looks for one or more character that is not a double quote.\n- `\"` is a literal double quote. It matches the closing double quote.\n\nWhen Vim sees the first `\"`, it begins the pattern capture. The moment it sees the second double quote in a line, it matches the second `\"` pattern and stops the pattern capture. Meanwhile, all non-double-quote characters inbetween are captured by the `[^\"]\\+` pattern, in this case, the phrase `Vim is awesome!`. This is a common pattern to capture a phrase surrounded by a pair of similar delimiters.\n\n- To capture a phrase surrounded by single quotes, you can use `/'[^']\\+'`.\n- To capture a phrase surrounded by zeroes, you can use `/0[^0]\\+0`.\n\n## Search Example: Capturing a Phone Number\n\nIf you want to match a US phone number separated by a hyphen (`-`), like `123-456-7890`, you can use:\n\n```\n/\\d\\{3\\}-\\d\\{3\\}-\\d\\{4\\}\n```\n\nUS Phone number consists of a set of three digit number, followed by another three digits, and finally by four digits. Let's break it down:\n- `\\d\\{3\\}` matches a digit repeated exactly three times\n- `-` is a literal hyphen\n\nYou can avoid typing escapes with `\\v`:\n\n```\n/\\v\\d{3}-\\d{3}-\\d{4}\n```\n\nThis pattern is also useful to capture any repeating digits, such as IP addresses and zip codes.\n\nThat covers the search part of this chapter. Now let's move to substitution.\n\n## Basic Substitution\n\nVim's substitute command is a useful command to quickly find and replace any pattern. The substitution syntax is:\n\n```\n:s/{old-pattern}/{new-pattern}/\n```\n\nLet's start with a basic usage. If you have this text:\n\n```\nvim is good\n```\n\nLet's substitute \"good\" with \"awesome\" because Vim is awesome. Run `:s/good/awesome/`. You should see:\n\n```\nvim is awesome\n```\n\n## Repeating the Last Substitution\n\nYou can repeat the last substitute command with either the normal command `&` or by running `:s`. If you have just run `:s/good/awesome/`, running either `&` or `:s` will repeat it.\n\nAlso, earlier in this chapter I mentioned that you can use `//` to repeat the previous search pattern.  This trick works with the substitution command. If `/good` was done recently and you leave the first substitute pattern argument blank, like in `:s//awesome/`, it works the same as running `:s/good/awesome/`.\n\n## Substitution Range\n\nJust like many Ex commands, you can pass a range argument into the substitute command. The syntax is:\n\n```\n:[range]s/old/new/\n```\n\nIf you have these expressions:\n\n```\nlet one = 1;\nlet two = 2;\nlet three = 3;\nlet four = 4;\nlet five = 5;\n```\n\nTo substitute the \"let\" into \"const\" on lines three to five, you can do:\n\n```\n:3,5s/let/const/\n```\n\nHere are some range variations you can pass:\n\n- `:,3s/let/const/` - if nothing is given before the comma, it represents the current line. Substitute from current line to line 3.\n- `:1,s/let/const/` - if nothing is given after the comma, it also represents the current line. Substitute from line 1 to current line.\n- `:3s/let/const/` - if only one value is given as range (no comma), it does substitution on that line only.\n\nIn Vim, `%` usually means the entire file. If you run `:%s/let/const/`, it will do substitution on all lines. Keep in mind this range syntax. Many command-line commands that you will learn in the upcoming chapters will follow this form.\n\n## Pattern Matching\n\nThe next few sections will cover basic regular expressions. A strong pattern knowledge is essential to master the substitute command.\n\nIf you have the following expressions:\n\n```\nlet one = 1;\nlet two = 2;\nlet three = 3;\nlet four = 4;\nlet five = 5;\n```\n\nTo add a pair of double quotes around the digits:\n\n```\n:%s/\\d/\"\\0\"/\n```\n\nThe result:\n\n```\nlet one = \"1\";\nlet two = \"2\";\nlet three = \"3\";\nlet four = \"4\";\nlet five = \"5\";\n```\n\nLet's break down the command:\n- `:%s` targets the entire file to perform substitution.\n- `\\d` is Vim's predefined range for digits (similar to using `[0-9]`).\n- `\"\\0\"` here the double quotes are literal double quotes. `\\0` is a special character representing \"the whole matched pattern\". The matched pattern here is a single digit number, `\\d`.\n\nAlternatively, `&` also represents the whole matched pattern like `\\0`. `:s/\\d/\"&\"/` would have also worked.\n\nLet's consider another example. Given these expressions and you need to swap all the \"let\" with the variable names.\n\n```\none let = \"1\";\ntwo let = \"2\";\nthree let = \"3\";\nfour let = \"4\";\nfive let = \"5\";\n```\n\nTo do that, run:\n\n```\n:%s/\\(\\w\\+\\) \\(\\w\\+\\)/\\2 \\1/\n```\n\nThe command above contains too many backslashes and is hard to read. In this case it is more convenient to use the `\\v` operator:\n\n```\n:%s/\\v(\\w+) (\\w+)/\\2 \\1/\n```\n\nThe result:\n\n```\nlet one = \"1\";\nlet two = \"2\";\nlet three = \"3\";\nlet four = \"4\";\nlet five = \"5\";\n```\n\nGreat! Let's break down that command:\n- `:%s` targets all the lines in the file to perform substitution.\n- `(\\w+) (\\w+)` is a group match. `\\w` is one of Vim's predefined ranges for a word character (`[0-9A-Za-z_]`). The `( )` surrounding it captures a word character match in a group. Notice the space between the two groupings. `(\\w+) (\\w+)` captures two groups. The first group captures \"one\" and the second group captures \"two\".\n- `\\2 \\1` returns the captured group in a reversed order. `\\2` contains the captured string \"let\" and `\\1` the string \"one\". Having `\\2 \\1` returns the string \"let one\".\n\nRecall that `\\0` represents the entire matched pattern. You can break the matched string into smaller groups with `( )`. Each group is represented by `\\1`, `\\2`, `\\3`, etc.\n\nLet's do one more example to solidify this group match concept. If you have these numbers:\n\n```\n123\n456\n789\n```\n\nTo reverse the order, run:\n\n```\n:%s/\\v(\\d)(\\d)(\\d)/\\3\\2\\1/\n```\n\nThe result is:\n\n```\n321\n654\n987\n```\n\nEach `(\\d)` matches each digit and creates a group. On the first line, the first `(\\d)` has a value of 1, the second `(\\d)` has a value of 2, and the third `(\\d)` has a value of 3. They are stored in the variables `\\1`, `\\2`, and `\\3`. In the second half of your substitution, the new pattern `\\3\\2\\1` results in the \"321\" value on line one.\n\nIf you had run this instead:\n\n```\n:%s/\\v(\\d\\d)(\\d)/\\2\\1/\n```\nYou would have gotten a different result:\n\n```\n312\n645\n978\n```\n\nThis is because you now only have two groups. The first group, captured by `(\\d\\d)`, is stored within `\\1` and has the value of 12. The second group, captured by `(\\d)`, is stored inside `\\2` and has the value of 3. `\\2\\1` then, returns 312.\n\n## Substitution Flags\n\nIf you have the sentence:\n\n```\nchocolate pancake, strawberry pancake, blueberry pancake\n```\n\nTo substitute all the pancakes into donuts, you cannot just run:\n\n```\n:s/pancake/donut\n```\n\nThe command above will only substitute the first match, giving you:\n\n```\nchocolate donut, strawberry pancake, blueberry pancake\n```\n\nThere are two ways to solve this. You can either run the substitute command twice more or you can pass it a global (`g`) flag to substitute all of the matches in a line.\n\nLet's talk about the global flag. Run:\n\n```\n:s/pancake/donut/g\n```\n\nVim substitutes all pancakes with donuts in one swift command. The global command is one of the several flags the substitute command accepts. You pass flags at the end of the substitute command. Here is a list of useful flags:\n\n```\n&    Reuse the flags from the previous substitute command.\ng    Replace all matches in the line.\nc    Ask for substitution confirmation.\ne    Prevent error message from displaying when substitution fails.\ni    Perform case insensitive substitution.\nI    Perform case sensitive substitution.\n```\n\nThere are more flags that I do not list above. To read about all the flags, check out `:h s_flags`.\n\nBy the way, the repeat-substitution commands (`&` and `:s`) do not retain the flags. Running `&` will only repeat `:s/pancake/donut/` without `g`. To quickly repeat the last substitute command with all the flags, run `:&&`.\n\n## Changing the Delimiter\n\nIf you need to replace a URL with a long path:\n\n```\nhttps://mysite.com/a/b/c/d/e\n```\n\nTo substitute it with the word \"hello\", run:\n\n```\n:s/https:\\/\\/mysite.com\\/a\\/b\\/c\\/d\\/e/hello/\n```\n\nHowever, it is hard to tell which forward slashes (`/`) are part of the substitution pattern and which ones are the delimiters. You can change the delimiter with any single-byte characters (except for alphabets, numbers, or `\"`, `|`, and `\\`). Let's replace them with `+`. The substitution command above then can be rewritten as:\n\n```\n:s+https:\\/\\/mysite.com\\/a\\/b\\/c\\/d\\/e+hello+\n```\n\nIt is now easier to see where the delimiters are.\n\n## Special Replace\n\nYou can also modify the case of the text you are substituting. Given the following expressions and your task is to uppercase the variables \"one\", \"two\", \"three\", etc.\n\n```\nlet one = \"1\";\nlet two = \"2\";\nlet three = \"3\";\nlet four = \"4\";\nlet five = \"5\";\n```\n\nRun:\n\n```\n:%s/\\v(\\w+) (\\w+)/\\1 \\U\\2/\n```\n\nYou will get:\n\n```\nlet ONE = \"1\";\nlet TWO = \"2\";\nlet THREE = \"3\";\nlet FOUR = \"4\";\nlet FIVE = \"5\";\n```\n\nThe breakdown:\n- `(\\w+) (\\w+)` captures the first two matched groups, such as \"let\" and \"one\".\n- `\\1` returns the value of the first group, \"let\".\n- `\\U\\2` uppercases (`\\U`) the second group (`\\2`).\n\nThe trick of this command is the expression `\\U\\2`. `\\U` instructs the following character to be uppercased.\n\nLet's do one more example. Suppose you are writing a Vim guide and you need to capitalize the first letter of each word in a line.\n\n```\nvim is the greatest text editor in the whole galaxy\n```\n\nYou can run:\n\n```\n:s/\\<./\\U&/g\n```\n\nThe result:\n\n```\nVim Is The Greatest Text Editor In The Whole Galaxy\n```\n\nHere is the breakdown:\n- `:s` substitutes the current line.\n- `\\<.` is comprised of two parts: `\\<` to match the start of a word and `.` to match any character. `\\<` operator makes the following character to be the first character of a word. Since `.` is the next character, it will match the first character of any word.\n- `\\U&`  uppercases the subsequent symbol, `&`. Recall that `&` (or `\\0`) represents the whole match. It matches the first character of any word.\n- `g` the global flag. Without it, this command only substitutes the first match. You need to substitute every match on this line.\n\nTo learn more of substitution's special replace symbols like `\\U`, check out `:h sub-replace-special`.\n\n## Alternative Patterns\n\nSometimes you need to match multiple patterns simultaneously. If you have the following greetings:\n\n```\nhello vim\nhola vim\nsalve vim\nbonjour vim\n```\n\nYou need to substitute the word \"vim\" with \"friend\" but only on the lines containing the word \"hello\" or \"hola\". Recall from earlier this chapter, you can use `|` for multiple alternative patterns.\n\n```\n:%s/\\v(hello|hola) vim/\\1 friend/g\n```\n\nThe result:\n\n```\nhello friend\nhola friend\nsalve vim\nbonjour vim\n```\n\nHere is the breakdown:\n- `%s` runs the substitute command on each line in a file.\n- `(hello|hola)` matches *either* \"hello\" or \"hola\" and considers it as a group.\n- `vim` is the literal word \"vim\".\n- `\\1` is the first group, which is either the text \"hello\" or \"hola\".\n- `friend` is the literal word \"friend\".\n\n## Substituting the Start and the End of a Pattern\n\nRecall that you can use `\\zs` and `\\ze` to define the start and the end of a match. This technique works in substitution too. If you have:\n\n```\nchocolate pancake\nstrawberry sweetcake\nblueberry hotcake\n```\n\nTo substitute the \"cake\" in \"hotcake\" with \"dog\" to get a \"hotdog\":\n\n```\n:%s/hot\\zscake/dog/g\n```\n\nResult:\n\n```\nchocolate pancake\nstrawberry sweetcake\nblueberry hotdog\n```\n\n## Greedy and Non-greedy\n\nYou can substitute the nth match in a line with this trick:\n\n```\nOne Mississippi, two Mississippi, three Mississippi, four Mississippi, five Mississippi.\n```\n\nTo substitute the third \"Mississippi\" with \"Arkansas\", run:\n\n```\n:s/\\v(.{-}\\zsMississippi){3}/Arkansas/g\n```\n\nThe breakdown:\n- `:s/` the substitute command.\n- `\\v` is the magic keyword so you don't have to escape special keywords.\n- `.` matches any single character.\n- `{-}` performs non-greedy match of 0 or more of the preceding atom.\n- `\\zsMississippi` makes \"Mississippi\" the start of the match.\n- `(...){3}` looks for the third match.\n\nYou have seen the `{3}` syntax earlier in this chapter. In this case, `{3}` will match exactly the third match. The new trick here is `{-}`. It is a non-greedy match. It finds the shortest match of the given pattern. In this case, `(.{-}Mississippi)` matches the least amount of \"Mississippi\" preceded by any character. Contrast this with `(.*Mississippi)` where it finds the longest match of the given pattern.\n\nIf you use `(.{-}Mississippi)`, you get five matches: \"One Mississippi\", \"Two Mississippi\", etc. If you use `(.*Mississippi)`, you get one match: the last \"Mississippi\". `*` is a greedy matcher and `{-}` is a non-greedy matcher. To learn more check out `:h /\\{-` and `:h non-greedy`.\n\nLet's do a simpler example. If you have the string:\n\n```\nabc1de1\n```\n\nYou can match \"abc1de1\" (greedy) with:\n\n```\n/a.*1\n```\n\nYou can match \"abc1\" (non-greedy) with:\n\n```\n/a.\\{-}1\n```\n\nSo if you need to uppercase the longest match (greedy), run:\n\n```\n:s/a.*1/\\U&/g\n```\n\nTo get:\n\n```\nABC1DEFG1\n```\n\nIf you need to uppercase the shortest match (non-greedy), run:\n\n```\n:s/a.\\{-}1/\\U&/g\n```\n\nTo get:\n\n```\nABC1defg1\n```\n\nIf you're new to greedy vs non-greedy concept, it can get hard to wrap your head around it. Experiment around with different combinations until you understand it.\n\n## Substituting Across Multiple Files\n\nFinally, let's learn how to substitute phrases across multiple files. For this section, assume that you have two files: `food.txt` and `animal.txt`.\n\nInside `food.txt`:\n\n```\ncorndog\nhotdog\nchilidog\n```\n\nInside `animal.txt`:\n\n```\nlarge dog\nmedium dog\nsmall dog\n```\n\nAssume your directory structure looks like this:\n\n```\n- food.txt\n- animal.txt\n```\n\nFirst, capture both `food.txt` and `animal.txt` inside `:args`. Recall from earlier chapters that `:args` can be used to create a list of file names. There are several ways to do this from inside Vim, one of them is by running this from inside Vim:\n\n```\n:args *.txt                  captures all txt files in current location\n```\n\nTo test it, when you run `:args`, you should see:\n\n```\n[food.txt] animal.txt\n```\n\nNow that all the relevant files are stored inside the argument list, you can perform a multi-file substitution with the `:argdo` command. Run:\n\n```\n:argdo %s/dog/chicken/\n```\n\nThis performs substitution against the all files inside the `:args` list. Finally, save the changed files with:\n\n```\n:argdo update\n```\n\n`:args` and `:argdo` are  useful tools to apply command line commands across multiple files. Try it with other commands!\n\n## Substituting Across Multiple Files With Macros\n\nAlternatively, you can also run the substitute command across multiple files with macros. Run:\n\n```\n:args *.txt\nqq\n:%s/dog/chicken/g\n:wnext\nq\n99@q\n```\n\nThe breakdown:\n- `:args *.txt` adds all text files into the `:args` list.\n- `qq` starts the macro in the \"q\" register.\n- `:%s/dog/chicken/g` substitutes \"dog\" with \"chicken\" on all lines in the current file.\n- `:wnext` saves the file then go to the next file on the `args` list.\n- `q` stops the macro recording.\n- `99@q` executes the macro ninety-nine times. Vim will stop the macro execution after it encounters the first error, so Vim won't actually execute the macro ninety-nine times.\n\n## Learning Search and Substitution the Smart Way\n\nThe ability to do search well is a necessary skill in editing. Mastering the search lets you utilize the flexibility of regular expressions to search for any pattern in a file. Take your time to learn these. To get better with regular expression you need to be actively using regular expressions. I once read a book about regular expression without actually doing it and I forgot almost everything I read afterwards. Active coding is the best way to master any skill.\n\nA good way to improve your pattern matching skill is whenever you need to search for a pattern (like \"hello 123\"), instead of querying for the literal search term (`/hello 123`), try to come up with a pattern for it (something like `/\\v(\\l+) (\\d+)`). Many of these regular expression concepts are also applicable in general programming, not only when using Vim.\n\nNow that you learned about advanced search and substitution in Vim, let's learn one of the most versatile commands, the global command.\n\n## Link\n- Prev [Ch11. Visual Mode](./ch11_visual_mode.md)\n- Next [Ch13. The Global Command](./ch13_the_global_command.md)\n"
  },
  {
    "path": "ch13_the_global_command.md",
    "content": "# Ch13. The Global Command\n\nSo far you have learned how to repeat the last change with the dot command (`.`), to replay actions with macros (`q`), and to store texts in the registers (`\"`).\n\nIn this chapter, you will learn how to repeat a command-line command with the global command.\n\n## Global Command Overview\n\nVim's global command is used to run a command-line command on multiple lines simultaneously.\n\nBy the way, you may have heard of the term \"Ex Commands\" before. In this guide, I refer to them as command-line commands. Both Ex commands and command-line commands are the same. They are the commands that start with a colon (`:`). The substitute command in the last chapter was an example of an Ex command. They are called Ex because they originally came from the Ex text editor. I will continue to refer to them as command-line commands in this guide. For a full list of Ex commands, check out `:h ex-cmd-index`.\n\nThe global command has the following syntax:\n\n```\n:g/pattern/command\n```\n\nThe `pattern` matches all lines containing that pattern, similar to the pattern in the substitute command. The `command` can be any command-line command. The global command works by executing `command` against each line that matches the `pattern`.\n\nIf you have the following expressions:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n\nconst two = 2;\nconsole.log(\"two: \", two);\n\nconst three = 3;\nconsole.log(\"three: \", three);\n```\n\nTo remove all lines containing \"console\", you can run:\n\n```\n:g/console/d\n```\n\nResult:\n\n```\nconst one = 1;\n\nconst two = 2;\n\nconst three = 3;\n```\n\nThe global command executes the delete command (`d`) on all lines that match the \"console\" pattern.\n\nWhen running the `g` command, Vim  makes two scans across the file. On the first run, it scans each line and marks the line that matches the `/console/` pattern. Once all the matching lines are marked, it goes for the second time and executes the `d` command on the marked lines.\n\nIf you want to delete all lines containing \"const\" instead, run:\n\n```\n:g/const/d\n```\n\nResult:\n\n```\nconsole.log(\"one: \", one);\n\nconsole.log(\"two: \", two);\n\nconsole.log(\"three: \", three);\n```\n\n## Inverse Match\n\nTo run the global command on non-matching lines, you can run:\n\n```\n:g!/pattern/command\n```\n\nor\n\n```\n:v/pattern/command\n```\n\nIf you run `:v/console/d`, it will delete all lines *not* containing \"console\".\n\n## Pattern\n\nThe global command uses the same pattern system as the substitute command, so this section will serve as a refresher.  Feel free to skip to the next section or read along!\n\nIf you have these expressions:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n\nconst two = 2;\nconsole.log(\"two: \", two);\n\nconst three = 3;\nconsole.log(\"three: \", three);\n```\n\nTo delete the lines containing either \"one\" or \"two\", run:\n\n```\n:g/one\\|two/d\n```\n\nTo delete the lines containing any single digits, run either:\n\n```\n:g/[0-9]/d\n```\n\nor\n\n```\n:g/\\d/d\n```\n\nIf you have the expression:\n\n```\nconst oneMillion = 1000000;\nconst oneThousand = 1000;\nconst one = 1;\n```\n\nTo match the lines containing between three to six zeroes, run:\n\n```\n:g/0\\{3,6\\}/d\n```\n\n## Passing a Range\n\nYou can pass a range before the `g` command. Here are some ways you can do it:\n- `:1,5g/console/d`  matches the string \"console\" between lines 1 and 5 and deletes them.\n- `:,5g/console/d` if there is no address before the comma, then it starts from the current line. It looks for the string \"console\" between the current line and line 5 and deletes them.\n- `:3,g/console/d` if there is no address after the comma, then it ends at the current line. It looks for the string \"console\" between line 3 and the current line and deletes them.\n- `:3g/console/d` if you only pass one address without a comma, it executes the command only on line 3. It looks on line 3 and deletes it if has the string \"console\".\n\nIn addition to numbers, you can also use these symbols as range:\n- `.` means the current line. A range of `.,3` means between the current line and line 3.\n- `$` means the last line in the file. `3,$` range means between line 3 and the last line.\n- `+n` means n lines after the current line. You can use it with `.` or without. `3,+1` or `3,.+1` means between line 3 and the line after the current line.\n\nIf you don't give it any range, by default it affects the entire file. This is actually not the norm. Most of Vim's command-line commands run on only the current line if you don't pass it any range. The two notable exceptions are the global (`:g`) and the save (`:w`) commands.\n\n## Normal Command\n\nYou can run a normal command with the global command with `:normal` command-line command.\n\nIf you have this text:\n```\nconst one = 1\nconsole.log(\"one: \", one)\n\nconst two = 2\nconsole.log(\"two: \", two)\n\nconst three = 3\nconsole.log(\"three: \", three)\n```\n\nTo add a \";\" to the end of each line, run:\n\n```\n:g/./normal A;\n```\n\nLet's break it down:\n- `:g` is the global command.\n- `/./` is a pattern for \"non-empty lines\". It matches the lines with at least one character, so it matches the lines with \"const\" and \"console\" and it does not match empty lines.\n- `normal A;` runs the `:normal` command-line command. `A;` is the normal mode command to insert a \";\" at the end of the line.\n\n## Executing a Macro\n\nYou can also execute a macro with the global command. A macro can be executed with the `normal` command. If you have the expressions:\n\n```\nconst one = 1\nconsole.log(\"one: \", one);\n\nconst two = 2\nconsole.log(\"two: \", two);\n\nconst three = 3\nconsole.log(\"three: \", three);\n```\n\nNotice that the lines with \"const\" do not have semi-colons. Let's create a macro to add a comma to the end of those lines in the register a:\n\n```\nqaA;<Esc>q\n```\n\nIf you need a refresher, check out the chapter on macro. Now run:\n\n```\n:g/const/normal @a\n```\n\nNow all lines with \"const\" will have a \";\" at the end.\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n\nconst two = 2;\nconsole.log(\"two: \", two);\n\nconst three = 3;\nconsole.log(\"three: \", three);\n```\n\nIf you followed this step-by-step, you will have two semi-colons on the first line. To avoid that, run the global command on line two onward, `:2,$g/const/normal @a`.\n\n## Recursive Global Command\n\nThe global command itself is a type of a command-line command, so you can technically run the global command inside a global command.\n\nGiven the following expressions, if you want to delete the second `console.log` statement:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n\nconst two = 2;\nconsole.log(\"two: \", two);\n\nconst three = 3;\nconsole.log(\"three: \", three);\n```\n\nIf you run:\n\n```\n:g/console/g/two/d\n```\n\nFirst, `g` will look for the lines containing the pattern \"console\" and will find 3 matches. Then the second `g` will look for the line containing the pattern \"two\" from those three matches. Finally, it will delete that match.\n\nYou can also combine `g` with `v` to find positive and negative patterns. For example:\n\n```\n:g/console/v/two/d\n```\n\nInstead of looking for the line containing the pattern \"two\", it will look for the lines *not* containing the pattern \"two\".\n\n## Changing the Delimiter\n\nYou can change the global command's delimiter like the substitute command. The rules are the same: you can use any single byte character except for alphabets, numbers, `\"`, `|`, and `\\`.\n\nTo delete the lines containing \"console\":\n\n```\n:g@console@d\n```\n\nIf you are using the substitute command with the global command, you can have two different delimiters:\n\n```\ng@one@s+const+let+g\n```\n\nHere the global command will look for all lines containing \"one\". The substitute command will substitute, from those matches, the string \"const\" with \"let\".\n\n## The Default Command\n\nWhat happens if you don't specify any command-line command in the global command?\n\nThe global command will use the print (`:p`) command to print the current line's text. If you run:\n\n```\n:g/console\n```\n\nIt will print at the bottom of the screen all the lines containing \"console\".\n\nBy the way, here is one interesting fact. Because the default command used by the global command is `p`, this makes the `g` syntax to be:\n\n```\n:g/re/p\n```\n\n- `g` = the global command\n- `re` = the regex pattern\n- `p` = the print command\n\nIt spells *\"grep\"*, the same `grep` from the command line. This is **not** a coincidence. The `g/re/p` command originally came from the Ed Editor, one of the original line text editors. The `grep` command got its name from Ed.\n\nYour computer probably still has the Ed editor. Run `ed` from the terminal (hint: to quit, type `q`).\n\n## Reversing the Entire Buffer\n\nTo reverse the entire file, run:\n\n```\n:g/^/m 0\n```\n\n`^` is a pattern for the beginning of a line. Use `^` to match all lines, including empty lines.\n\nIf you need to reverse only a few lines, pass it a range. To reverse the lines between line five to line ten, run:\n\n```\n:5,10g/^/m 0\n```\n\nTo learn more about the move command, check out `:h :move`.\n\n## Aggregating All Todos\n\nWhen coding, sometimes I would write TODOs in the file I'm editing:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n// TODO: feed the puppy\n\nconst two = 2;\n// TODO: feed the puppy automatically\nconsole.log(\"two: \", two);\n\nconst three = 3;\nconsole.log(\"three: \", three);\n// TODO: create a startup selling an automatic puppy feeder\n```\n\nIt can be hard to keep track of all the created TODOs. Vim has a `:t` (copy) method to copy all matches to an address. To learn more about the copy method, check out `:h :copy`.\n\nTo copy all TODOs to the end of the file for easier introspection, run:\n\n```\n:g/TODO/t $\n```\n\nResult:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n// TODO: feed the puppy\n\nconst two = 2;\n// TODO: feed the puppy automatically\nconsole.log(\"two: \", two);\n\nconst three = 3;\nconsole.log(\"three: \", three);\n// TODO: create a startup selling an automatic puppy feeder\n\n// TODO: feed the puppy\n// TODO: feed the puppy automatically\n// TODO: create a startup selling an automatic puppy feeder\n```\n\nNow I can review all the TODOs I created, find a time to do them or delegate them to someone else, and continue to work on my next task.\n\nIf instead of copying them you want to move all the TODOs to the end, use the move command, `:m`:\n\n```\n:g/TODO/m $\n```\n\nResult:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n\nconst two = 2;\nconsole.log(\"two: \", two);\n\nconst three = 3;\nconsole.log(\"three: \", three);\n\n// TODO: feed the puppy\n// TODO: feed the puppy automatically\n// TODO: create a startup selling an automatic puppy feeder\n```\n\n## Black Hole Delete\n\nRecall from the register chapter that deleted texts are stored inside the numbered registers (granted they are sufficiently large ). Whenever you run `:g/console/d`, Vim stores the deleted lines in the numbered registers. If you delete many lines, you can quickly fill up all the numbered registers. To avoid this, you can always use the black hole register (`\"_`) to *not* store your deleted lines into the registers. Run:\n\n```\n:g/console/d_\n```\n\nBy passing `_` after `d`, Vim won't use up your scratch registers.\n\n## Reduce Multiple Empty Lines to One Empty Line\n\nIf you have a text with multiple empty lines:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n\n\nconst two = 2;\nconsole.log(\"two: \", two);\n\n\n\n\n\nconst three = 3;\nconsole.log(\"three: \", three);\n```\n\nYou can quickly reduce the empty lines into one empty line with:\n\n```\n:g/^$/,/./-1j\n```\n\nResult:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\n\nconst two = 2;\nconsole.log(\"two: \", two);\n\nconst three = 3;\nconsole.log(\"three: \", three);\n```\n\nNormally the global command accepts the following form: `:g/pattern/command`. However, you can also run the global command with the following form: `:g/pattern1/,/pattern2/command`. With this, Vim will apply the `command` within `pattern1` and `pattern2`.\n\nWith that in mind, let's break down the command `:g/^$/,/./-1j` according to `:g/pattern1/,/pattern2/command`:\n- `/pattern1/` is `/^$/`. It represents an empty line (a line with zero character).\n- `/pattern2/` is `/./` with `-1` line modifier. `/./` represents a non-empty line (a line with at least one character). The `-1` means the line above that.\n- `command` is `j`, the join command (`:j`). In this context, this global command joins all the given lines.\n\nBy the way, if you want to reduce multiple empty lines to no lines, run this instead:\n\n```\n:g/^$/,/./j\n```\n\nA simpler alternative:\n\n```\n:g/^$/-j\n```\n\nYour text is now reduced to:\n\n```\nconst one = 1;\nconsole.log(\"one: \", one);\nconst two = 2;\nconsole.log(\"two: \", two);\nconst three = 3;\nconsole.log(\"three: \", three);\n```\n\n## Advanced Sort\n\nVim has a `:sort` command to sort the lines within a range. For example:\n\n```\nd\nb\na\ne\nc\n```\n\nYou can sort them by running `:sort`. If you give it a range, it will sort only the lines within that range. For example, `:3,5sort` only sorts lines three and five.\n\nIf you have the following expressions:\n\n```\nconst arrayB = [\n  \"i\",\n  \"g\",\n  \"h\",\n  \"b\",\n  \"f\",\n  \"d\",\n  \"e\",\n  \"c\",\n  \"a\",\n]\n\nconst arrayA = [\n  \"h\",\n  \"b\",\n  \"f\",\n  \"d\",\n  \"e\",\n  \"a\",\n  \"c\",\n]\n```\n\nIf you need to sort the elements inside the arrays, but not the arrays themselves, you can run this:\n\n```\n:g/\\[/+1,/\\]/-1sort\n```\n\nResult:\n\n```\nconst arrayB = [\n  \"a\",\n  \"b\",\n  \"c\",\n  \"d\",\n  \"e\",\n  \"f\",\n  \"g\",\n  \"h\",\n  \"i\",\n]\n\nconst arrayA = [\n  \"a\"\n  \"b\",\n  \"c\",\n  \"d\",\n  \"e\",\n  \"f\",\n  \"h\",\n]\n```\n\nThis is great! But the command looks complicated. Let's break it down. This command also follows the form `:g/pattern1/,/pattern2/command`.\n\n- `:g` is the global command pattern.\n- `/\\[/+1` is the first pattern. It matches a literal left square bracket \"[\". The `+1` refers to the line below it.\n- `/\\]/-1` is the second pattern. It matches a literal right square bracket \"]\". The `-1` refers to the line above it.\n- `/\\[/+1,/\\]/-1` then refers to any lines between \"[\" and \"]\".\n- `sort` is a command-line command to sort.\n\n## Learn the Global Command the Smart Way\n\nThe global command executes the command-line command against all matching lines. With it, you only need to run a command once and Vim will do the rest for you. To become proficient at the global command, two things are required: a good vocabulary of command-line commands and a knowledge of regular expressions. As you spend more time using Vim, you will naturally learn more command-line commands. A regular expression knowledge will require a more active approach. But once you become comfortable with regular expressions, you will be ahead of many.\n\nSome of the examples here are complicated. Do not be intimidated. Really take your time to understand them. Learn to read the patterns. Do not give up.\n\nWhenever you need to run multiple commands, pause and see if you can use the `g` command. Identify the best command for the job and write a pattern to target as many things at once.\n\nNow that you know how powerful the global command is, let's learn how to use the external commands to increase your tool arsenal.\n\n## Link\n- Prev [Ch12. Search and Substitute](./ch12_search_and_substitute.md)\n- Next [Ch14. External Commands](./ch14_external_commands.md)\n"
  },
  {
    "path": "ch14_external_commands.md",
    "content": "# Ch14. External Commands\n\nInside the Unix system, you will find many small, hyper-specialized commands that do one thing (and do it well). You can chain these commands to work together to solve a complex problem. Wouldn't it be great if you could use these commands from inside Vim?\n\nDefinitely. In this chapter, you will learn how to extend Vim to work seamlessly with external commands.\n\n## The Bang Command\n\nVim has a bang (`!`) command that can do three things:\n\n1. Read the STDOUT of an external command into the current buffer.\n2. Write the content of your buffer as the STDIN to an external command.\n3. Execute an external command from inside Vim.\n\nLet's go through each of them.\n\n## Reading the STDOUT of a Command Into Vim\n\nThe syntax to read the STDOUT of an external command into the current buffer is:\n\n```\n:r !cmd\n```\n\n`:r` is Vim's read command. If you use it without `!`, you can use it to get the content of a file. If you have a file `file1.txt` in the current directory and you run:\n\n```\n:r file1.txt\n```\n\nVim will put the content of `file1.txt` into the current buffer.\n\nIf you run the `:r` command followed by a `!` and an external command, the output of that command will be inserted into the current buffer. To get the result of the `ls` command, run:\n\n```\n:r !ls\n```\n\nIt returns something like:\n\n```\nfile1.txt\nfile2.txt\nfile3.txt\n```\n\nYou can read the data from the `curl` command:\n\n```\n:r !curl -s 'https://jsonplaceholder.typicode.com/todos/1'\n```\n\nThe `r` command also accepts an address:\n\n```\n:10r !cat file1.txt\n```\n\nNow the STDOUT from running `cat file1.txt` will be inserted after line 10.\n\n## Writing the Buffer Content Into an External Command\n\nThe command `:w`, in addition to saving a file, can be used to pass the text in the current buffer as the STDIN for an external command. The syntax is:\n\n```\n:w !cmd\n```\n\nIf you have these expressions:\n\n```\nconsole.log(\"Hello Vim\");\nconsole.log(\"Vim is awesome\");\n```\n\nMake sure you have [node](https://nodejs.org/en/) installed in your machine, then run:\n\n```\n:w !node\n```\n\nVim will use `node` to execute the JavaScript expressions to print \"Hello Vim\" and \"Vim is awesome\".\n\nWhen using the `:w` command, Vim uses all texts in the current buffer, similar to the global command (most command-line commands, if you don't pass it a range, only executes the command against the current line). If you pass `:w` a specific address:\n\n```\n:2w !node\n```\n\nVim only uses the text from the second line into the `node` interpreter.\n\nThere is a subtle but significant difference between `:w !node` and `:w! node`. With `:w !node`, you are \"writing\" the text in the current buffer into the external command `node`. With `:w! node`, you are force-saving a file and naming the file \"node\".\n\n## Executing an External Command\n\nYou can execute an external command from inside Vim with the bang command. The syntax is:\n\n```\n:!cmd\n```\n\nTo see the content of the current directory in the long format, run:\n\n```\n:!ls -ls\n```\n\nTo kill a process that is running on PID 3456, you can run:\n\n```\n:!kill -9 3456\n```\n\nYou can run any external command without leaving Vim so you can stay focused on your task.\n\n## Filtering Texts\n\nIf you give `!` a range, it can be used to filter texts. Suppose you have the following texts:\n\n```\nhello vim\nhello vim\n```\n\nLet's uppercase the current line using the `tr` (translate) command. Run:\n\n```\n:.!tr '[:lower:]' '[:upper:]'\n```\n\nThe result:\n\n```\nHELLO VIM\nhello vim\n```\n\nThe breakdown:\n- `.!` executes the filter command on the current line.\n- `tr '[:lower:]' '[:upper:]'` calls the `tr` command to replace all lowercase characters with uppercase ones.\n\nIt is imperative to pass a range to run the external command as a filter. If you try running the command above without the `.` (`:!tr '[:lower:]' '[:upper:]'`), you will see an error.\n\nLet's assume that you need to remove the second column on both lines with the `awk` command:\n\n```\n:%!awk \"{print $1}\"\n```\n\nThe result:\n\n```\nhello\nhello\n```\n\nThe breakdown:\n- `:%!` executes the filter command on all lines (`%`).\n- `awk \"{print $1}\"` prints only the first column of the match.\n\nYou can chain multiple commands with the chain operator (`|`) just like in the terminal. Let's say you have a file with these delicious breakfast items:\n\n```\nname price\nchocolate pancake 10\nbuttermilk pancake 9\nblueberry pancake 12\n```\n\nIf you need to sort them based on the price and display only the menu with an even spacing, you can run:\n\n```\n:%!awk 'NR > 1' | sort -nk 3 | column -t\n```\n\nThe result:\n```\nbuttermilk pancake 9\nchocolate pancake 10\nblueberry pancake 12\n```\n\nThe breakdown:\n- `:%!` applies the filter to all lines (`%`).\n- `awk 'NR > 1'` displays the texts only from row number two onwards.\n- `|` chains the next command.\n- `sort -nk 3` sorts numerically (`n`) using the values from column 3 (`k 3`).\n- `column -t` organizes the text with even spacing.\n\n## Normal Mode Command\n\nVim has a filter operator (`!`) in the normal mode. If you have the following greetings:\n\n```\nhello vim\nhola vim\nbonjour vim\nsalve vim\n```\n\nTo uppercase the current line and the line below, you can run:\n```\n!jtr '[a-z]' '[A-Z]'\n```\n\nThe breakdown:\n- `!j` runs the normal command filter operator (`!`) targetting the current line and the line below it. Recall that because it is a normal mode operator, the grammar rule `verb + noun` applies. `!` is the verb and `j` is the noun.\n- `tr '[a-z]' '[A-Z]'` replaces the lowercase letters with the uppercase letters.\n\nThe filter normal command only works on motions / text objects that are at least one line or longer. If you had tried running `!iwtr '[a-z]' '[A-Z]'` (execute `tr` on inner word), you will find that it applies the `tr` command on the entire line, not the word your cursor is on.\n\n## Learn External Commands the Smart Way\n\nVim is not an IDE. It is a lightweight modal editor that is highly extensible by design. Because of this extensibility, you have an easy access to any external command in your system. Armed with these external commands, Vim is one step closer from becoming an IDE. Someone said that the Unix system is the first IDE ever.\n\nThe bang command is as useful as how many external commands you know. Don't worry if your external command knowledge is limited. I still have a lot to learn too. Take this as a motivation for continuous learning. Whenever you need to modify a text, look if there is an external command that can solve your problem. Don't worry about mastering everything, just learn the ones you need to complete the current task.\n\n## Link\n- Prev [Ch13. The Global Command](./ch13_the_global_command.md)\n- Next [Ch15. Command-line Mode](./ch15_command-line_mode.md)\n"
  },
  {
    "path": "ch15_command-line_mode.md",
    "content": "# Ch15. Command-line Mode\n\nIn the last three chapters, you learned how to use the search commands (`/`, `?`), substitute command (`:s`), global command (`:g`), and external command (`!`). These are examples of command-line mode commands.\n\nIn this chapter, you will learn various tips and tricks for the command-line mode.\n\n## Entering and Exiting the Command-line Mode\n\nThe command-line mode is a mode in itself, just like normal mode, insert mode, and visual mode. When you are in this mode, the cursor goes to the bottom of the screen where you can type in different commands.\n\nThere are 4 different commands you can use to enter the command-line mode:\n- Search patterns (`/`, `?`)\n- Command-line commands (`:`)\n- External commands (`!`)\n\nYou can enter the command-line mode from the normal mode or the visual mode.\n\nTo leave the command-line mode, you can use `<Esc>`, `Ctrl-C`, or `Ctrl-[`.\n\n*Other literatures might refer the \"Command-line command\" as \"Ex command\" and the \"External command\" as \"filter command\" or \"bang operator\".*\n\n## Repeating the Previous Command\n\nYou can repeat the previous command-line command or external command with `@:`.\n\nIf you just ran `:s/foo/bar/g`, running `@:` repeats that substitution. If you just ran `:.!tr '[a-z]' '[A-Z]'`, running `@:` repeats the last external command translation filter.\n\n## Command-line Mode Shortcuts\n\nWhile in the command-line mode, you can move to the left or to the right, one character at a time, with the `Left` or `Right` arrow.\n\nIf you need to move word-wise, use `Shift-Left` or `Shift-Right` (in some OS, you might have to use `Ctrl` instead of `Shift`).\n\nTo go to the start of the line, use `Ctrl-B`. To go to the end of the line, use `Ctrl-E`.\n\nSimilar to the insert mode, inside the command-line mode, you have three ways to delete characters:\n\n```\nCtrl-H    Delete one character\nCtrl-W    Delete one word\nCtrl-U    Delete the entire line\n```\nFinally, if you want to edit the command like you would a normal textfile use `Ctrl-F`.\n\nThis also allows you to search through the previous commands, edit them and rerun them by pressing `<Enter>` in \"command-line editing normal mode\".\n\n## Register and Autocomplete\n\nWhile in the command-line mode, you can insert texts from Vim register with `Ctrl-R` the same way as the insert mode. If you have the string \"foo\" saved in the register a, you can insert it by running `Ctrl-R a`. Everything that you can get from the register in the insert mode, you can do the same from the command-line mode.\n\nIn addition, you can also get the word under the cursor with `Ctrl-R Ctrl-W` (`Ctrl-R Ctrl-A` for the WORD under cursor). To get the line under the cursor, use `Ctrl-R Ctrl-L`. To get the filename under the cursor, use `Ctrl-R Ctrl-F`.\n\nYou can also autocomplete existing commands. To autocomplete the `echo` command, while in the command-line mode, type \"ec\", then press `<Tab>`. You should see on the bottom left Vim commands starting with \"ec\" (example: `echo echoerr echohl echomsg econ`). To go to the next option, press either `<Tab>` or `Ctrl-N`. To go the previous option, press either `<Shift-Tab>` or `Ctrl-P`.\n\nSome command-line commands accept file names as arguments. One example is `edit`. You can autocomplete here too. After typing the command, `:e ` (don't forget the space), press `<Tab>`. Vim will list all the relevant file names that you can choose from so you don't have to type it from scratch.\n\n## History Window and Command-line Window\n\nYou can view the history of command-line commands and search terms (this requires the `+cmdline_hist` feature).\n\nTo open the command-line history, run `:his :`. You should see something like the following:\n\n```\n## Cmd history\n2  e file1.txt\n3  g/foo/d\n4  s/foo/bar/g\n```\n\nVim lists the history of all the `:` commands you run. By default, Vim stores the last 50 commands. To change the amount of the entries that Vim remembers to 100, you run `set history=100`.\n\nA more useful use of the command-line history is through the command-line window, `q:`. This will open a searchable, editable history window. Suppose you have these expressions in the history when you press `q:`:\n\n```\n51  s/verylongsubstitutionpattern/pancake/g\n52  his :\n53  wq\n```\n\nIf your current task is to do `s/verylongsubstitutionpattern/donut/g`, instead of typing the command from scratch, why don't you reuse `s/verylongsubstitutionpattern/pancake/g`? After all, the only thing that's different is the word substitute, \"donut\" vs \"pancake\". Everything else is the same.\n\nAfter you ran `q:`, find that `s/verylongsubstitutionpattern/pancake/g` in the history (you can use the Vim navigation in this environment) and edit it directly! Change \"pancake\" to \"donut\" inside the history window, then press `<Enter>`. Boom! Vim executes `s/verylongsubstitutionpattern/donut/g` for you. Super convenient!\n\nSimilarly, to view the search history, run `:his /` or `:his ?`. To open the search history window where you can search and edit past history, run `q/` or `q?`.\n\nTo quit this window, press `Ctrl-C`, `Ctrl-W C`, or type `:quit`.\n\n## More Command-line Commands\n\nVim has hundreds of built-in commands. To see all the commands Vim has, check out `:h ex-cmd-index` or `:h :index`.\n\n## Learn Command-line Mode the Smart Way\n\nCompared to the other three modes, the command-line mode is like the Swiss Army knife of text editing. You can edit text, modify files, and execute commands, just to name a few. This chapter is a collection of odds and ends of the command-line mode. It also brings Vim modes into closure. Now that you know how to use the normal, insert, visual, and command-line mode you can edit text with Vim faster than ever.\n\nIt's time to move away from Vim modes and learn how to do an even faster navigation with Vim tags.\n\n## Link\n- Prev [Ch14. External Commands](./ch14_external_commands.md)\n- Next [Ch16. Tags](./ch16_tags.md)\n"
  },
  {
    "path": "ch16_tags.md",
    "content": "# Ch16. Tags\n\nOne useful feature in text editing is being able to go to any definition quickly. In this chapter, you will learn how to use Vim tags to do that.\n\n## Tag Overview\n\nSuppose someone handed you a new codebase:\n\n```\none = One.new\none.donut\n```\n\n`One`? `donut`? Well, these might have been obvious to the developers writing the code way back then, but now those developers are no longer here and it is up to you to understand this obscure code. One way to help understand this is to follow the source code where `One` and `donut` are defined.\n\nYou can search for them with either `fzf` or `grep` (or `vimgrep`), but in this case, tags are faster.\n\nThink of tags like an address book:\n\n```\nName    Address\nIggy1   1234 Cool St, 11111\nIggy2   9876 Awesome Ave, 2222\n```\n\nInstead of having a name-address pair, tags store definitions paired with addresses.\n\nLet's assume that you have these two Ruby files inside the same directory:\n\n```\n## one.rb\nclass One\n  def initialize\n    puts \"Initialized\"\n  end\n\n  def donut\n    puts \"Bar\"\n  end\nend\n```\n\nand\n\n```\n## two.rb\nrequire './one'\n\none = One.new\none.donut\n```\n\nTo jump to a definition, you can use `Ctrl-]` in the normal mode. Inside `two.rb`, go to the line where `one.donut` is and move the cursor over `donut`. Press `Ctrl-]`.\n\nWhoops, Vim could not find the tag file. You need to generate the tag file first.\n\n## Tag Generator\n\nModern Vim does not come with tag generator, so you will have to download an external tag generator. There are several options to choose:\n\n- ctags = C only. Available almost everywhere.\n- exuberant ctags = One of the most popular ones. Has many language support.\n- universal ctags = Similar to exuberant ctags, but newer.\n- etags = For Emacs. Hmm...\n- JTags = Java\n- ptags.py = Python\n- ptags = Perl\n- gnatxref = Ada\n\nIf you look at Vim tutorials online, many will recommend [exuberant ctags](http://ctags.sourceforge.net/). It supports [41 programming languages](http://ctags.sourceforge.net/languages.html). I used it and it worked great. However, because it has not been maintained since 2009, Universal ctags would be a better choice. It works similar to exuberant ctags and is currently being maintained.\n\nI won't go into details on how to install the universal ctags. Check out the [universal ctags](https://github.com/universal-ctags/ctags) repository for more instructions.\n\nAssuming you have the universal ctags installed, let's generate a basic tag file. Run:\n\n```\nctags -R .\n```\n\nThe `R` option tells ctags to run a recursive scan from your current location (`.`). You should see a `tags` file in your current directory. Inside you will see something like this:\n\n```\n!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/\n!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/\n!_TAG_OUTPUT_FILESEP\tslash\t/slash or backslash/\n!_TAG_OUTPUT_MODE\tu-ctags\t/u-ctags or e-ctags/\n!_TAG_PATTERN_LENGTH_LIMIT\t96\t/0 for no limit/\n!_TAG_PROGRAM_AUTHOR\tUniversal Ctags Team\t//\n!_TAG_PROGRAM_NAME\tUniversal Ctags\t/Derived from Exuberant Ctags/\n!_TAG_PROGRAM_URL\t<https://ctags.io/>\t/official site/\n!_TAG_PROGRAM_VERSION\t0.0.0\t/b43eb39/\nOne\tone.rb\t/^class One$/;\"\tc\ndonut\tone.rb\t/^  def donut$/;\"\tf\tclass:One\ninitialize\tone.rb\t/^  def initialize$/;\"\tf\tclass:One\n```\n\nYours might look a little different depending on your Vim setting and the ctags generator. A tag file is composed of two parts: the tag metadata and the tag list. These metadata (`!TAG_FILE...`) are usually controlled by the ctags generator. I won't discuss it here, but feel free to check their docs for more! The tag list is a list of all the definitions indexed by ctags.\n\nNow go to `two.rb`, put the cursor on `donut`, and type `Ctrl-]`. Vim will take you to the file `one.rb` on the line where `def donut` is. Success! But how did Vim do this?\n\n## Tags Anatomy\n\nLet's look at the `donut` tag item:\n\n```\ndonut\tone.rb\t/^  def donut$/;\"\tf\tclass:One\n```\n\nThe above tag item is composed of four components: a `tagname`, a `tagfile`, a `tagaddress`, and tag options.\n- `donut` is the `tagname`. When your cursor is on \"donut\", Vim searches the tag file for a line that has the \"donut\" string.\n- `one.rb` is the `tagfile`. Vim looks for a file `one.rb`.\n- `/^ def donut$/` is the `tagaddress`. `/.../` is a pattern indicator. `^` is a pattern for the first element on a line. It is followed by two spaces, then the string `def donut`. Finally, `$` is a pattern for the last element on a line.\n- `f class:One` is the tag option that tells Vim that the function `donut` is a function (`f`) and is part of the `One` class.\n\nLet's look at another item in the tag list:\n\n```\nOne\tone.rb\t/^class One$/;\"\tc\n```\n\nThis line works the same way as the `donut` pattern:\n\n- `One` is the `tagname`. Note that with tags, the first scan is case sensitive. If you have `One` and `one` on the list, Vim will prioritize `One` over `one`.\n- `one.rb` is the `tagfile`. Vim looks for a file `one.rb`.\n- `/^class One$/` is the `tagaddress` pattern. Vim looks for a line that starts with (`^`) `class` and ends with (`$`) `One`.\n- `c` is one of the possible tag options. Since `One` is a ruby class and not a procedure, it marks it with a `c`.\n\nDepending on which tag generator you use, the content of your tag file may look different. At minimum, a tag file must have either one of these formats:\n\n```\n1.  {tagname} {TAB} {tagfile} {TAB} {tagaddress}\n2.  {tagname} {TAB} {tagfile} {TAB} {tagaddress} {term} {field} ..\n```\n\n## The Tag File\n\nYou have learned that a new file, `tags`, is created after running `ctags -R .`. How does Vim know where to look for the tag file?\n\nIf you run `:set tags?`, you might see `tags=./tags,tags` (depending on your Vim settings, it might be different). Here Vim looks for all tags in the path of the current file in the case of `./tags` and the current directory (your project root) in the case of `tags`.\n\nAlso in the case of `./tags`, Vim will first look for a tag file inside the path of your current file regardless how nested it is, then it will look for a tag file of the current directory (project root). Vim stops after it finds the first match.\n\nIf your `'tags'` file had said `tags=./tags,tags,/user/iggy/mytags/tags`, then Vim will also look at the `/user/iggy/mytags` directory for a tag file after Vim finishes searching `./tags` and `tags` directory. You don't have to store your tag file inside your project, you can keep them separate.\n\nTo add a new tag file location, use the following:\n\n```\nset tags+=path/to/my/tags/file\n```\n\n## Generating Tags for a Large Project\n\nIf you tried to run ctags in a large project, it may take a long time because Vim also looks inside every nested directories. If you are a Javascript developer, you know that `node_modules` can be very large. Imagine if you have a five sub-projects and each contains its own `node_modules` directory. If you run `ctags -R .`, ctags will try to scan through all 5 `node_modules`. You probably don't need to run ctags on `node_modules`.\n\nTo run ctags excluding the `node_modules`, run:\n\n```\nctags -R --exclude=node_modules .\n```\n\nThis time it should take less than a second. By the way, you can use the `exclude` option multiple times:\n\n```\nctags -R --exclude=.git --exclude=vendor --exclude=node_modules --exclude=db --exclude=log .\n```\n\nThe point is, if you want to omit a directory, `--exclude` is your best friend.\n\n## Tags Navigation\n\nYou can get good mileage using only `Ctrl-]`, but let's learn a few more tricks. The tag jump key `Ctrl-]` has a command-line mode alternative: `:tag {tag-name}`. If you run:\n\n```\n:tag donut\n```\n\nVim will jump to the `donut` method, just like doing `Ctrl-]` on \"donut\" string. You can autocomplete the argument too, with `<Tab>`:\n\n```\n:tag d<Tab>\n```\n\nVim lists all tags that starts with \"d\". In this case, \"donut\".\n\nIn a real project, you may encounter multiple methods with the same name. Let's update the two ruby files from earlier. Inside `one.rb`:\n\n```\n## one.rb\nclass One\n  def initialize\n    puts \"Initialized\"\n  end\n\n  def donut\n    puts \"one donut\"\n  end\n\n  def pancake\n    puts \"one pancake\"\n  end\nend\n```\n\nInside `two.rb`:\n\n```\n## two.rb\nrequire './one.rb'\n\ndef pancake\n  \"Two pancakes\"\nend\n\none = One.new\none.donut\nputs pancake\n```\n\nIf you are coding along, don't forget to run `ctags -R .` again since you now have several new procedures. You have two instances of the `pancake` procedure. If you are inside `two.rb` and you pressed `Ctrl-]`, what would happen?\n\nVim will jump to `def pancake` inside `two.rb`, not the `def pancake` inside `one.rb`. This is because Vim sees the `pancake` procedure inside `two.rb` as having a higher priority than the other `pancake` procedure.\n\n## Tag Priority\n\nNot all tags are equal. Some tags have higher priorities. If Vim is presented with duplicate item names, Vim checks the priority of the keyword. The order is:\n\n1. A fully matched static tag in the current file.\n2. A fully matched global tag in the current file.\n3. A fully matched global tag in a different file.\n4. A fully matched static tag in another file.\n5. A case-insensitively matched static tag in the current file.\n6. A case-insensitively matched global tag in the current file.\n7. A case-insensitively matched global tag in a different file.\n8. A case-insensitively matched static tag in the current file.\n\nAccording to the priority list, Vim prioritizes the exact match found on the same file. That's why Vim chooses the `pancake` procedure inside `two.rb` over the `pancake` procedure inside `one.rb`. There are some exceptions to the priority list above depending on your `'tagcase'`, `'ignorecase'`, and `'smartcase'` settings, but I will not discuss them here. If you are interested, check out `:h tag-priority`.\n\n## Selective Tag Jumps\n\nIt would be nice if you can choose which tag items to jump to instead of always going to the highest priority tag item. Maybe you actually need to jump to the `pancake` method in `one.rb` and not the one in `two.rb`. To do that, you can use `:tselect`. Run:\n\n```\n:tselect pancake\n```\n\nYou will see, on the bottom of the screen:\n\n```\n## pri kind tag               file\n1 F C f    pancake           two.rb\n             def pancake\n2 F   f    pancake           one.rb\n             class:One\n             def pancake\n```\n\nIf you type 2, Vim will jump to the procedure in `one.rb`. If you type 1, Vim will jump to the procedure in `two.rb`.\n\nPay attention to the `pri` column. You have `F C` on the first match and `F` on the second match. This is what Vim uses to determine the tag priority. `F C` means a fully-matched (`F`) global tag in the current (`C`) file. `F` means only a fully-matched (`F`) global tag. `F C` always have a higher priority than `F`.\n\nIf you run `:tselect donut`, Vim also prompts you to select which tag item to jump to, even though there is only one option to choose from. Is there a way for Vim to prompt the tag list only if there are multiple matches and to jump immediately if there is only one tag found?\n\nOf course! Vim has a `:tjump` method. Run:\n\n```\n:tjump donut\n```\n\nVim will immediately jump to the `donut` procedure in `one.rb`, much like running `:tag donut`. Now run:\n\n```\n:tjump pancake\n```\n\nVim will prompt you tag options to choose from, much like running `:tselect pancake`. With `tjump` you get the best of both methods.\n\nVim has a normal mode key for `tjump`: `g Ctrl-]`. I personally like `g Ctrl-]` better than `Ctrl-]`.\n\n## Autocompletion With Tags\n\nTags can assist autocompletions. Recall from chapter 6, Insert Mode, that you can use `Ctrl-X` sub-mode to do various autocompletions. One autocompletion sub-mode that I did not mention was `Ctrl-]`. If you do `Ctrl-X Ctrl-]` while in the insert mode, Vim will use the tag file for autocompletion.\n\nIf you go into the insert mode and type `Ctrl-x Ctrl-]`, you will see:\n\n```\nOne\ndonut\ninitialize\npancake\n```\n\n## Tag Stack\n\nVim keeps a list of all the tags you have jumped to and from in a tag stack. You can see this stack with `:tags`. If you had first tag-jumped to `pancake`, followed by `donut`, and run `:tags`, you will see:\n\n```\n  # TO tag         FROM line  in file/text\n  1  1 pancake            10  ch16_tags/two.rb\n  2  1 donut               9  ch16_tags/two.rb\n>\n```\n\nNote the `>` symbol above. It shows your current position in the stack. To \"pop\" the stack to go back to one previous stack, you can run `:pop`. Try it, then run `:tags` again:\n\n```\n  # TO tag         FROM line  in file/text\n  1  1 pancake            10  puts pancake\n> 2  1 donut               9  one.donut\n\n```\n\nNote that the `>` symbol is now on line two, where the `donut` is. `pop` one more time, then run `:tags` again:\n\n```\n  # TO tag         FROM line  in file/text\n> 1  1 pancake            10  puts pancake\n  2  1 donut               9  one.donut\n```\n\nIn normal mode, you can run `Ctrl-t` to achieve the same effect as `:pop`.\n\n## Automatic Tag Generation\n\nOne of the biggest drawbacks of Vim tags is that each time you make a significant change, you have to regenerate the tag file. If you recently renamed the `pancake` procedure to the `waffle` procedure, the tag file did not know that the `pancake` procedure had been renamed. It still stored `pancake` in the list of tags. You have to run `ctags -R .` to create an updated tag file. Recreating a new tag file this way can be cumbersome.\n\nLuckily there are several methods you can employ to generate tags automatically. \n\n## Generate a Tag on Save\n\nVim has an autocommand (`autocmd`) method to execute any command on an event trigger. You can use this to generate tags on each save. Run:\n\n```\n:autocmd BufWritePost *.rb silent !ctags -R .\n```\n\nBreakdown:\n- `autocmd` is a command-line command. It accepts an event, file pattern, and a command.\n- `BufWritePost` is an event for saving a buffer. Each time you save a file, you trigger a `BufWritePost` event.\n- `.rb` is a file pattern for ruby files.\n- `silent` is actually part of the command you are passing. Without this, Vim will display `press ENTER or type command to continue` each time you trigger the autocommand.\n- `!ctags -R .` is the command to execute. Recall that `!cmd` from inside Vim executes terminal command.\n\nNow each time you save from inside a ruby file, Vim will run `ctags -R .`.\n\n## Using Plugins\n\nThere are several plugins to generate ctags automatically:\n\n- [vim-gutentags](https://github.com/ludovicchabant/vim-gutentags)\n- [vim-tags](https://github.com/szw/vim-tags)\n- [vim-easytags](https://github.com/xolox/vim-easytags)\n- [vim-autotag](https://github.com/craigemery/vim-autotag)\n\nI use vim-gutentags. It is simple to use and will work right out of the box.\n\n## Ctags and Git Hooks\n\nTim Pope, author of many great Vim plugins, wrote a blog suggesting to use git hooks. [Check it out](https://tbaggery.com/2011/08/08/effortless-ctags-with-git.html).\n\n## Learn Tags the Smart Way\n\nA tag is useful once configured properly. Suppose you are faced with a new codebase and you want to understand what `functionFood` does, you can easily read it by jumping to its definition. Inside it, you learn that it also calls `functionBreakfast`. You follow it and you learn that it calls `functionPancake`. Your function call graph looks something like this:\n\n```\nfunctionFood -> functionBreakfast -> functionPancake\n```\n\nThis gives you insight that this code flow is related to having a pancake for breakfast.\n\nTo learn more about tags, check out `:h tags`. Now that you know how to use tags, let's explore a different feature: folding.\n\n## Link\n- Prev [Ch15. Command-line Mode](./ch15_command-line_mode.md)\n- Next [Ch17. Fold](./ch17_fold.md)\n"
  },
  {
    "path": "ch17_fold.md",
    "content": "# Ch17. Fold\n\nWhen you read a file, often there are many irrelevant texts that hinder you from understanding what that file does. To hide the unnecessary noise, use Vim fold.\n\nIn this chapter, you will learn different ways to fold a file.\n\n## Manual Fold\n\nImagine that you are folding a sheet of paper to cover some text. The actual text does not go away, it is still there. Vim fold works the same way. It folds a range of text, hiding it from display without actually deleting it.\n\nThe fold operator is `z` (when a paper is folded, it is shaped like the letter z).\n\nSuppose you have this text:\n\n```\nFold me\nHold me\n```\n\nWith the cursor in the first line, type `zfj`. Vim folds both lines into one. You should see something like this:\n\n```\n+-- 2 lines: Fold me -----\n```\n\nHere is the breakdown:\n- `zf` is the fold operator.\n- `j` is the motion for the fold operator.\n\nYou can open a folded text with `zo`. To close the fold, use `zc`.\n\nFold is an operator, so it follows the grammar rule (`verb + noun`). You can pass the fold operator with a motion or text object. To fold an inner paragraph, run `zfip`. To fold to the end of a file, run `zfG`. To fold the texts between `{` and `}`, run `zfa{`.\n\nYou can fold from the visual mode. Highlight the area you want to fold (`v`, `V`, or `Ctrl-v`), then run `zf`.\n\nYou can execute a fold from the command-line mode with the `:fold` command. To fold the current line and the line after it, run:\n\n```\n:,+1fold\n```\n\n`,+1` is the range. If you don't pass parameters to the range, it defaults to the current line. `+1` is the range indicator for the next line. To fold the lines 5 to 10, run `:5,10fold`. To fold from the current position to the end of the line, run `:,$fold`.\n\nThere are many other fold and unfold commands. I find them too many to remember when starting out. The most useful ones are:\n- `zR` to open all folds.\n- `zM` to close all folds.\n- `za` toggle a fold.\n\nYou can run `zR` and `zM` on any line, but `za` only works when you are on a folded / unfolded line. To learn more folding commands, check out `:h fold-commands`.\n\n## Different Fold Methods\n\nThe section above covers Vim's manual fold. There are six different folding methods in Vim:\n1. Manual\n2. Indent\n3. Expression\n4. Syntax\n5. Diff\n6. Marker\n\nTo see which folding method you are currently using, run `:set foldmethod?`. By default, Vim uses the `manual` method.\n\nIn the rest of the chapter, you will learn the other five folding methods. Let's get started with the indent fold.\n\n## Indent Fold\n\nTo use an indent fold, change the `'foldmethod'` to indent:\n\n```\n:set foldmethod=indent\n```\n\nSuppose that you have the text:\n\n```\nOne\n  Two\n  Two again\n```\n\nIf you run `:set foldmethod=indent`, you will see:\n\n```\nOne\n+-- 2 lines: Two -----\n```\n\nWith indent fold, Vim looks at how many spaces each line has at the beginning and compares it with the `'shiftwidth'` option to determine its foldability. `'shiftwidth'` returns the number of spaces required for each step of the indent. If you run:\n\n```\n:set shiftwidth?\n```\n\nVim's default `'shiftwidth'` value is 2. On the text above, there are two spaces between the start of the line and the text \"Two\" and \"Two again\". When Vim sees the number of spaces and that the `'shiftwidth'` value is 2, Vim considers that line to have an indent fold level of one.\n\nSuppose this time you have only one space between the start of the line and the text:\n\n```\nOne\n Two\n Two again\n```\n\nRight now if you run `:set foldmethod=indent`, Vim does not fold the indented line because there isn't sufficient space on each line. One space is not considered an indentation. However, if you change the `'shiftwidth'` to 1:\n\n```\n:set shiftwidth=1\n```\n\nThe text is now foldable. It is now considered an indentation. \n\nRestore the `shiftwidth` back to 2 and the spaces between the texts to two again. In addition, add two additional texts:\n\n```\nOne\n  Two\n  Two again\n    Three\n    Three again\n```\n\nRun fold (`zM`), you will see:\n\n```\nOne\n+-- 4 lines: Two -----\n```\n\nUnfold the folded lines (`zR`), then put your cursor on \"Three\" and toggle the text's folding state (`za`):\n\n```\nOne\n  Two\n  Two again\n+-- 2 lines: Three -----\n```\n\nWhat's this? A fold within a fold?\n\nNested folds are valid. The text \"Two\" and \"Two again\" have fold level of one. The text \"Three\" and \"Three again\" have fold level of two. If you have a foldable text with a higher fold level within a foldable text, you will have multiple fold layers.\n\n## Expression Fold\n\nExpression fold allows you to define an expression to match for a fold. After you define the fold expressions, Vim scans each line for the value of `'foldexpr'`. This is the variable that you have to configure to return the appropriate value. If the `'foldexpr'` returns 0, then the line is not folded. If it returns 1, then that line has a fold level of 1. If it returns 2, then that line has a fold level of 2. There are more values other than integers, but I won't go over them. If you are curious, check out `:h fold-expr`.\n\nFirst, let's change the foldmethod:\n\n```\n:set foldmethod=expr\n```\n\nSuppose you have a list of breakfast foods and you want to fold all breakfast items starting with \"p\":\n\n```\ndonut\npancake\npop-tarts\nprotein bar\nsalmon\nscrambled eggs\n```\n\nNext, change the `foldexpr` to capture the expressions starting with \"p\":\n\n```\n:set foldexpr=getline(v:lnum)[0]==\\\\\"p\\\\\"\n```\n\nThe expression above looks complicated. Let's break it down:\n- `:set foldexpr` sets up the `'foldexpr'` option to accept a custom expression.\n- `getline()` is a Vimscript function that returns the content of any given line. If you run `:echo getline(5)`, it will return the content of line 5.\n- `v:lnum` is Vim's special variable for the `'foldexpr'` expression. Vim scans each line and at that moment stores each line's number in `v:lnum` variable. On line 5, `v:lnum` has value of 5. On line 10, `v:lnum` has value of 10.\n- `[0]` in the context of `getline(v:lnum)[0]` is the first character of each line. When Vim scans a line, `getline(v:lnum)` returns the content of each line. `getline(v:lnum)[0]` returns the first character of each line. On the first line of our list, \"donut\", `getline(v:lnum)[0]` returns \"d\". On the second line of our list, \"pancake\", `getline(v:lnum)[0]` returns \"p\".\n- `==\\\\\"p\\\\\"` is the second half of the equality expression. It checks if the expression you just evaluated is equal to \"p\". If it is true, it returns 1. If it is false, it returns 0. In Vim, 1 is truthy and 0 is falsy. So on the lines that start with an \"p\", it returns 1. Recall if a `'foldexpr'` has a value of 1, then it has a fold level of 1.\n\nAfter running this expression, you should see:\n\n```\ndonut\n+-- 3 lines: pancake -----\nsalmon\nscrambled eggs\n```\n\n## Syntax Fold\n\nSyntax fold is determined by syntax language highlighting. If you use a language syntax plugin like [vim-polyglot](https://github.com/sheerun/vim-polyglot), the syntax fold will work right out of the box. Just change the fold method to syntax:\n\n```\n:set foldmethod=syntax\n```\n\nLet's assume you are editing a JavaScript file and you have vim-polyglot installed. If you have an array like the following:\n\n```\nconst nums = [\n  one,\n  two,\n  three,\n  four\n]\n```\n\nIt will be folded with a syntax fold. When you define a syntax highlighting for a particular language (typically inside the `syntax/` directory), you can add a `fold` attribute to make it foldable. Below is a snippet from vim-polyglot JavaScript syntax file. Notice the `fold` keyword at the end.\n\n```\nsyntax region  jsBracket                      matchgroup=jsBrackets            start=/\\[/ end=/\\]/ contains=@jsExpression,jsSpreadExpression extend fold\n```\n\nThis guide won't cover the `syntax` feature. If you're curious, check out `:h syntax.txt`.\n\n## Diff Fold\n\nVim can do a diff procedure to compare two or more files.\n\nIf you have `file1.txt`:\n\n```\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\n```\n\nAnd `file2.txt`:\n\n```\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nemacs is ok\n```\n\nRun `vimdiff file1.txt file2.txt`:\n\n```\n+-- 3 lines: vim is awesome -----\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\nvim is awesome\n[vim is awesome] / [emacs is ok]\n```\n\nVim automatically folds some of the identical lines. When you are running the `vimdiff` command, Vim automatically uses `foldmethod=diff`. If you run `:set foldmethod?`, it will return `diff`.\n\n## Marker Fold\n\nTo use a marker fold, run:\n\n```\n:set foldmethod=marker\n```\n\nSuppose you have the text:\n\n```\nHello\n\n{{{\nworld\nvim\n}}}\n```\n\nRun `zM`, you will see:\n\n```\nhello\n\n+-- 4 lines: -----\n```\n\nVim sees `{{{` and `}}}` as fold indicators and folds the texts between them. With the marker fold, Vim looks for special markers, defined by `'foldmarker'` option, to mark folding areas. To see what markers Vim uses, run:\n\n```\n:set foldmarker?\n```\n\nBy default, Vim uses `{{{` and `}}}` as indicators. If you want to change the indicator to another texts, like \"coffee1\" and \"coffee2\":\n\n```\n:set foldmarker=coffee1,coffee2\n```\n\nIf you have the text:\n\n```\nhello\n\ncoffee1\nworld\nvim\ncoffee2\n```\n\nNow Vim uses `coffee1` and `coffee2` as the new folding markers. As a side note, an indicator must be a literal string and cannot be a regex.\n\n## Persisting Fold\n\nYou lose all fold information when you close the Vim session. If you have this file, `count.txt`:\n\n```\none\ntwo\nthree\nfour\nfive\n```\n\nThen do a manual fold from line \"three\" down (`:3,$fold`):\n\n```\none\ntwo\n+-- 3 lines: three ---\n```\n\nWhen you exit Vim and reopen `count.txt`, the folds are no longer there!\n\nTo preserve the folds, after folding, run:\n\n```\n:mkview\n```\n\nThen when you open up `count.txt`, run:\n\n```\n:loadview\n```\n\nYour folds are restored. However, you have to manually run `mkview` and `loadview`. I know that one of these days, I will forget to run `mkview` before closing the file and I will lose all the folds. How can we automate this process?\n\nTo automatically run `mkview` when you close a `.txt` file and run `loadview` when you open a `.txt` file, add this in your vimrc:\n\n```\nautocmd BufWinLeave *.txt mkview\nautocmd BufWinEnter *.txt silent loadview\n```\n\nRecall that `autocmd` is used to execute a command on an event trigger. The two events here are:\n- `BufWinLeave` for when you remove a buffer from a window.\n- `BufWinEnter` for when you load a buffer in a window.\n\nNow after you fold inside a `.txt` file and exit Vim, the next time you open that file, your fold information will be restored.\n\nBy default, Vim saves the fold information when running `mkview` inside `~/.vim/view` for the Unix system. For more information, check out `:h 'viewdir'`.\n\n## Learn Fold the Smart Way\n\nWhen I first started Vim, I neglected to learn fold because I didn't think it was useful. However, the longer I code, the more useful I find folding is. Strategically placed folds can give you a better overview of the text structure, like a book's table of content.\n\nWhen you learn fold, start with the manual fold because that can be used on-the-go. Then gradually learn different tricks to do indent and marker folds. Finally, learn how to do syntax and expression folds. You can even use the latter two to write your own Vim plugins.\n\n## Link\n- Prev [Ch16. Tags](./ch16_tags.md)\n- Next [Ch18. Git](./ch18_git.md)\n"
  },
  {
    "path": "ch18_git.md",
    "content": "# Ch18. Git\n\nVim and git are two great tools for two different things. Git is a version control tool. Vim is a text editor.\n\nIn this chapter, you will learn different ways to integrate Vim and git together.\n\n## Diffing\n\nRecall in the previous chapter, you can run a `vimdiff` command to show the differences between multiple files.\n\nSuppose you have two files, `file1.txt` and `file2.txt`. \n\nInside `file1.txt`:\n\n```\npancakes\nwaffles\napples\n\nmilk\napple juice\n\nyogurt\n```\n\nInside `file2.txt`:\n\n```\npancakes\nwaffles\noranges\n\nmilk\norange juice\n\nyogurt\n```\n\nTo see the differences between both files, run:\n\n```\nvimdiff file1.txt file2.txt\n```\n\nAlternatively you could run:\n\n```\nvim -d file1.txt file2.txt\n```\n\n`vimdiff` displays two buffers side-by-side. On the left is `file1.txt` and on the right is `file2.txt`. The first differences (apples and oranges) are highlighted on both lines.\n\nSuppose you want to make the second buffer to have apples, not oranges. To transfer the content from your current position (you're currently on `file1.txt`) to `file2.txt`, first go to the next diff with `]c` (to jump to the previous diff window, use `[c`). The cursor should be on apples now. Run `:diffput`. Both files should now have apples.\n\nIf you need to transfer the text from the other buffer (orange juice, `file2.txt`) to replace the text on the current buffer (apple juice, `file1.txt`), with your cursor still on `file1.txt` window, first go to the next diff with `]c`. Your cursor now should be on apple juice. Run `:diffget` to get the orange juice from another buffer to replace apple juice in our buffer.\n\n`:diffput` *puts out* the text from the current buffer to another buffer. `:diffget` *gets* the text from another buffer to the current buffer.\n\nIf you have multiple buffers, you can run `:diffput fileN.txt` and `:diffget fileN.txt` to target the fileN buffer.\n\n## Vim As a Merge Tool\n\n> \"I love resolving merge conflicts!\" - Nobody\n\nI don't know anyone who likes resolving merge conflicts. However, they are inevitable. In this section, you will learn how to leverage Vim as a merge conflict resolution tool.\n\nFirst, change the default merge tool to use `vimdiff` by running:\n\n```\ngit config merge.tool vimdiff\ngit config merge.conflictstyle diff3\ngit config mergetool.prompt false\n```\n\nAlternatively, you can modify the `~/.gitconfig` directly (by default it should be in root, but yours might be in different place). The commands above should modify your gitconfig to look like the setting below, if you haven't run them already, you can also manually edit your gitconfig.\n\n```\n[core]\n  editor = vim\n[merge]\n  tool = vimdiff\n  conflictstyle = diff3\n[difftool]\n  prompt = false\n```\n\nLet's create a fake merge conflict to test this out. Create a directory `/food` and make it a git repository:\n\n```\ngit init\n```\n\nAdd a file, `breakfast.txt`. Inside:\n\n```\npancakes\nwaffles\noranges\n```\n\nAdd the file and commit it:\n\n```\ngit add .\ngit commit -m \"Initial breakfast commit\"\n```\n\nNext, create a new branch and call it apples branch:\n\n```\ngit checkout -b apples\n```\n\nChange the `breakfast.txt`:\n\n```\npancakes\nwaffles\napples\n```\n\nSave the file, then add and commit the change:\n\n```\ngit add .\ngit commit -m \"Apples not oranges\"\n```\n\nGreat. Now you have oranges in the master branch and apples in the apples branch. Let's return to the master branch:\n\n```\ngit checkout master\n```\n\nInside `breakfast.txt`, you should see the base text, oranges. Let's change it to grapes because they are in season right now:\n\n```\npancakes\nwaffles\ngrapes\n```\n\nSave, add, and commit:\n\n```\ngit add .\ngit commit -m \"Grapes not oranges\"\n```\n\nNow you are ready to merge the apples branch into the master branch:\n\n```\ngit merge apples\n```\n\nYou should see an error:\n\n```\nAuto-merging breakfast.txt\nCONFLICT (content): Merge conflict in breakfast.txt\nAutomatic merge failed; fix conflicts and then commit the result.\n```\n\nA conflict, great! Let's resolve the conflict using our newly-configured `mergetool`. Run:\n\n```\ngit mergetool\n```\n\nVim displays four windows. Pay attention to the top three:\n\n- `LOCAL` contains `grapes`. This is the change in \"local\", what you are merging into.\n- `BASE` contains `oranges`. This is the common ancestor between `LOCAL` and `REMOTE` to compare how they diverge.\n- `REMOTE` contains `apples`. This is what is being merged into.\n\nAt the bottom (the fourth window) you see:\n\n```\npancakes\nwaffles\n<<<<<<< HEAD\ngrapes\n||||||| db63958\noranges\n=======\napples\n>>>>>>> apples\n```\n\nThe fourth window contains the merge conflict texts. With this setup, it is easier to see what change each environment has. You can see the content from `LOCAL`, `BASE`, and `REMOTE` at the same time. \n\nYour cursor should be on the fourth windows, on the highlighted area. To get the change from `LOCAL` (grapes), run `:diffget LOCAL`. To get the change from `BASE` (oranges), run `:diffget BASE` and to get the change from `REMOTE` (apples), run `:diffget REMOTE`.\n\nIn this case, let's get the change from `LOCAL`. Run `:diffget LOCAL`. The fourth window will now have grapes. Save and exit all files (`:wqall`) when you are done. That wasn't bad, right?\n\nIf you notice, you also have a file `breakfast.txt.orig` now. Git creates a backup file in case things don't go well. If you don't want git to create a backup during a merge, run:\n\n```\ngit config --global mergetool.keepBackup false\n```\n\n## Git Inside Vim\n\nVim does not have a native git feature built-in. One way to run git commands from Vim is to use the bang operator, `!`, in the command-line mode.\n\nAny git command can be run with `!`:\n\n```\n:!git status\n:!git commit\n:!git diff\n:!git push origin master\n```\n\nYou can also use Vim's `%` (current buffer) or `#` (other buffer) conventions:\n\n```\n:!git add %         \" git add current file\n:!git checkout #    \" git checkout the other file\n```\n\nOne Vim trick you can use to add multiple files in different Vim window is to run:\n\n```\n:windo !git add %\n```\n\nThen make a commit:\n\n```\n:!git commit \"Just git-added everything in my Vim window, cool\"\n```\n\nThe `windo` command is one of Vim's \"do\" commands, similar to `argdo` that you saw previously. `windo` executes the command on each window.\n\nAlternatively, you can also use `bufdo !git add %` to git add all buffers or `argdo !git add %` to git add all the file arguments, depending on your workflow.\n\n## Plugins\n\nThere are many Vim plugins for git support. Below is a list of some of the popular git-related plugins for Vim (there is probably more at the time you read this):\n\n- [vim-gitgutter](https://github.com/airblade/vim-gitgutter)\n- [vim-signify](https://github.com/mhinz/vim-signify)\n- [vim-fugitive](https://github.com/tpope/vim-fugitive)\n- [gv.vim](https://github.com/junegunn/gv.vim)\n- [vimagit](https://github.com/jreybert/vimagit)\n- [vim-twiggy](https://github.com/sodapopcan/vim-twiggy)\n- [rhubarb](https://github.com/tpope/vim-rhubarb)\n\nOne of the most popular ones is vim-fugitive. For the remaining of the chapter, I will go over several git workflows using this plugin.\n\n## Vim-fugitive\n\nThe vim-fugitive plugin allows you to run the git CLI without leaving the Vim editor. You will find that some commands are better when executed from inside Vim.\n\nTo get started, install the vim-fugitive with a Vim plugin manager ([vim-plug](https://github.com/junegunn/vim-plug), [vundle](https://github.com/VundleVim/Vundle.vim), [dein.vim](https://github.com/Shougo/dein.vim), etc).\n\n## Git Status\n\nWhen you run the `:Git` command without any parameters, vim-fugitive displays a git summary window. It shows the untracked, unstaged, and staged file(s). While in this \"`git status`\" mode, you can do several things:\n- `Ctrl-N` / `Ctrl-P` to go up or down the file list.\n- `-` to stage or unstage the file name under the cursor.\n- `s` to stage the file name under the cursor.\n- `u` to unstage the file name under the cursor.\n- `>` / `<` to display or hide an inline diff of the file name under the cursor.\n\nFor more, check out `:h fugitive-staging-maps`.\n\n## Git Blame\n\nWhen you run the `:Git blame` command from the current file, vim-fugitive displays a split blame window. This can be useful to find the person responsible for writing that buggy line of code so you can yell at him / her (just kidding).\n\nSome things you can do while in this `\"git blame\"` mode:\n- `q` to close the blame window.\n- `A` to resize the author column.\n- `C` to resize the commit column.\n- `D` to resize the date / time column.\n\nFor more, check out `:h :Git_blame`.\n\n## Gdiffsplit\n\nWhen you run the `:Gdiffsplit` command, vim-fugitive runs a `vimdiff` of the current file's latest changes against the index or work tree. If you run `:Gdiffsplit <commit>`, vim-fugitive runs a `vimdiff` against that file inside `<commit>`.\n\nBecause you are in a `vimdiff` mode, you can *get* or *put* the diff with `:diffput` and `:diffget`.\n\n## Gwrite and Gread\n\nWhen you run the `:Gwrite` command in a file after you make changes, vim-fugitive stages the changes. It is like running `git add <current-file>`.\n\nWhen you run the `:Gread` command in a file after you make changes, vim-fugitive restores the file to the state prior to the changes. It is like running `git checkout <current-file>`. One advantage of running `:Gread` is the action is undo-able. If, after you run `:Gread`, you change your mind and want to keep the old change, you can just run undo (`u`) and Vim will undo the `:Gread` action. This would not have been possible if you had run `git checkout <current-file>` from the CLI.\n\n## Gclog\n\nWhen you run the `:Gclog` command, vim-fugitive displays the commit history. It is like running the `git log` command. Vim-fugitive uses Vim's quickfix to accomplish this, so you can use `:cnext` and `:cprevious` to traverse to the next or previous log information. You can open and close the log list with `:copen` and `:cclose`.\n\nWhile in this `\"git log\"` mode, you can do two things:\n- View the tree.\n- Visit the parent (the previous commit).\n\nYou can pass to `:Gclog` arguments just like the `git log` command. If your project has a long commit history and you only need to view the last three commits, you can run `:Gclog -3`. If you need to filter it based on the committer's date, you can run something like `:Gclog --after=\"January 1\" --before=\"March 14\"`.\n\n## More Vim-fugitive\n\nThese are only a few examples of what vim-fugitive can do. To learn more about vim-fugitive, check out `:h fugitive.txt`. Most of the popular git commands are probably optimized with vim-fugitive. You just have to look for them in the documentation.\n\nIf you are inside one of vim-fugitive's \"special mode\" (for example, inside `:Git` or `:Git blame` mode) and you want to learn what shortcuts are available, press `g?`. Vim-fugitive will display the appropriate `:help` window for the mode you are in. Neat!\n\n## Learn Vim and Git the Smart Way\n\nYou may find vim-fugitive to be a good complement to your workflow (or not). Regardless, I would strongly encourage you to check out all the plugins listed above. There are probably others I didn't list. Go try them out.\n\nOne obvious way to get better with Vim-git integration is to read more about git. Git, on its own, is a vast topic and I am only showing a fraction of it. With that, let's *git going* (pardon the pun) and talk about how to use Vim to compile your code!\n\n## Link\n- Prev [Ch17. Fold](./ch17_fold.md)\n- Next [Ch19. Compile](./ch19_compile.md)\n"
  },
  {
    "path": "ch19_compile.md",
    "content": "# Ch19. Compile\n\nCompiling is an important subject for many languages. In this chapter, you will learn how to compile from Vim. You will also look at ways to take advantage of Vim's `:make` command.\n\n## Compile From the Command Line\n\nYou can use the bang operator (`!`) to compile. If you need to compile your `.cpp` file with `g++`, run:\n\n```\n:!g++ hello.cpp -o hello\n```\n\nHowever, having to manually type the filename and the output filename each time is error-prone and tedious. A makefile is the way to go.\n\n## The Make Command\n\nVim has a `:make` command to run a makefile. When you run it, Vim looks for a makefile in the current directory to execute.\n\nCreate a file named `makefile` in the current directory and put these inside:\n\n```\nall:\n\techo \"Hello all\"\nfoo:\n\techo \"Hello foo\"\nlist_pls:\n\tls\n```\n\nRun this from Vim:\n\n```\n:make\n```\n\nVim executes it the same way as when you're running it from the terminal. The `:make` command accepts parameter just like the terminal make command. Run:\n\n```\n:make foo\n\" Outputs \"Hello foo\"\n\n:make list_pls\n\" Outputs the ls command result\n```\n\nThe `:make` command uses Vim's quickfix to store any error if you run a bad command. Let's run a nonexisting target:\n\n```\n:make dontexist\n```\n\nYou should see an error running that command. To view that error, run the quickfix command `:copen` to view the quickfix window:\n\n```\n|| make: *** No rule to make target `dontexist'.  Stop.\n```\n\n## Compiling With Make\n\nLet's use the makefile to compile a basic `.cpp` program. First, let's create a `hello.cpp` file:\n\n```\n#include <iostream>\n\nint main() {\n    std::cout << \"Hello!\\n\";\n    return 0;\n}\n```\n\nUpdate your makefile to build and run a `.cpp` file:\n\n```\nall:\n\techo \"build, run\"\nbuild:\n\tg++ hello.cpp -o hello\nrun:\n\t./hello\n```\n\nNow run:\n\n```\n:make build\n```\n\nThe `g++` compiles `./hello.cpp` and creates `./hello`. Then run:\n\n```\n:make run\n```\n\nYou should see `\"Hello!\"` printed on the terminal.\n\n## Different Make Program\n\nWhen you run `:make`, Vim actually runs whatever command that is set under the `makeprg` option. If you run `:set makeprg?`, you'll see:\n\n```\nmakeprg=make\n```\n\nThe default `:make` command is the `make` external command. To change the `:make` command to execute `g++ {your-file-name}` each time you run it, run:\n\n```\n:set makeprg=g++\\ %\n```\n\nThe `\\` is to escape the space after `g++`. The `%` symbol in Vim represents the current file. The command `g++\\ %` is equivalent to running `g++ hello.cpp`.\n\nGo to `./hello.cpp` then run `:make`. Vim compiles `hello.cpp` and creates `a.out` because you didn't specify the output. Let's refactor it so it will name the compiled output with the name of the original file minus the extension. Run or add this to vimrc:\n\n```\nset makeprg=g++\\ %\\ -o\\ %<\n```\n\nThe breakdown:\n- `g++\\ %` is the same as above. It is equivalent to running `g++ <your-file>`.\n- `-o` is the output option.\n- `%<` in Vim represents the current file name without an extension (`hello.cpp` becomes `hello`).\n\nWhen you run `:make` from inside `./hello.cpp`, it is compiled into `./hello`. To quickly execute `./hello` from inside `./hello.cpp`, run `:!./%<`. Again, this is the same as running `:!./{current-file-name-minus-the-extension}`.\n\nFor more, check out `:h :compiler` and `:h write-compiler-plugin`.\n\n## Auto-compile on Save\n\nYou can make life even easier by automating compilation. Recall that you can use Vim's `autocmd` to trigger automatic actions based on certain events. To automatically compile `.cpp` files on each save add this on your vimrc:\n\n```\nautocmd BufWritePost *.cpp make\n```\n\nEach time you save inside a `.cpp` file, Vim executes the `make` command.\n\n## Switching Compiler\n\nVim has a `:compiler` command to quickly switch compilers. Your Vim build probably comes with several pre-built compiler configurations. To check what compilers you have, run:\n\n```\n:e $VIMRUNTIME/compiler/<Tab>\n```\n\nYou should see a list of compilers for different programming languages.\n\nTo use the `:compiler` command, suppose you have a ruby file, `hello.rb` and inside it has:\n\n```\nputs \"Hello ruby\"\n```\n\nRecall that if you run `:make`, Vim executes whatever command is assigned to `makeprg` (default is `make`). If you run:\n\n```\n:compiler ruby\n```\n\nVim runs the `$VIMRUNTIME/compiler/ruby.vim` script and changes the `makeprg` to use the `ruby` command. Now if you run `:set makeprg?`, it should say `makeprg=ruby` (this depends on what is inside your `$VIMRUNTIME/compiler/ruby.vim` file or if you have another custom ruby compilers. Yours might be different). The `:compiler {your-lang}` command allows you to switch to different compilers  quickly. This is useful if your project uses multiple languages.\n\nYou don't have to use the `:compiler` and `makeprg` to compile a program. You can run a test script, lint a file, send a signal, or anything you want.\n\n## Creating a Custom Compiler\n\nLet's create a simple Typescript compiler. Install Typescript (`npm install -g typescript`) to your machine. You should now have the `tsc` command. If you haven't played with typescript before, `tsc` compiles a Typescript file into a Javascript file. Suppose that you have a file, `hello.ts`:\n\n```\nconst hello = \"hello\";\nconsole.log(hello);\n```\n\nIf you run `tsc hello.ts`, it will compile into `hello.js`. However, if you have the following expressions inside `hello.ts`:\n\n```\nconst hello = \"hello\";\nhello = \"hello again\";\nconsole.log(hello);\n```\n\nThis will throw an error because you can't mutate a `const` variable. Running `tsc hello.ts` will throw an error:\n\n```\nhello.ts:2:1 - error TS2588: Cannot assign to 'person' because it is a constant.\n\n2 person = \"hello again\";\n  ~~~~~~\n\n\nFound 1 error.\n```\n\nTo create a simple Typescript compiler, in your `~/.vim/` directory, add a `compiler` directory (`~/.vim/compiler/`), then create a `typescript.vim` file (`~/.vim/compiler/typescript.vim`). Put this inside:\n\n```\nCompilerSet makeprg=tsc\nCompilerSet errorformat=%f:\\ %m\n```\n\nThe first line sets the `makeprg` to run the `tsc` command. The second line sets the error format to display the file (`%f`), followed by a literal colon (`:`) and an escaped space (`\\ `), followed by the error message (`%m`). To learn more about the error formatting, check out `:h errorformat`.\n\nYou should also read some of the pre-made compilers to see how others do it. Check out `:e $VIMRUNTIME/compiler/<some-language>.vim`.\n\nBecause some plugins may interfere with the Typescript file, let's open the `hello.ts` without any plugin, using the `--noplugin` flag:\n\n```\nvim --noplugin hello.ts\n```\n\nCheck the `makeprg`:\n\n```\n:set makeprg?\n```\n\nIt should say the default `make` program. To use the new Typescript compiler, run:\n\n```\n:compiler typescript\n```\n\nWhen you run `:set makeprg?`, it should say `tsc` now. Let's put it to the test. Run:\n\n```\n:make %\n```\n\nRecall that `%` means the current file. Watch your Typescript compiler work as expected! To see the list of error(s), run `:copen`.\n\n## Async Compiler\n\nSometimes compiling can take a long time. You don't want to be staring at a frozen Vim while waiting for your compilation process to finish. Wouldn't it be nice if you could compile asynchronously so you can still use Vim during compilation?\n\nLuckily there are plugins to run async processes. The two big ones are:\n\n- [vim-dispatch](https://github.com/tpope/vim-dispatch)\n- [asyncrun.vim](https://github.com/skywind3000/asyncrun.vim)\n\nIn the remaining of this chapter, I will go over vim-dispatch, but I would strongly encourage you to try all of them out there.\n\n*Vim and NeoVim actually supports async jobs, but they are beyond the scope of this chapter. If you're curious, check out `:h job-channel-overview.txt`.*\n\n## Plugin: Vim-dispatch\n\nVim-dispatch has several commands, but the two main ones are `:Make` and `:Dispatch` commands.\n\n### Async Make\n\nVim-dispatch's `:Make` command is similar to Vim's `:make`, but it runs asynchronously. If you are in a Javascript project and you need to run `npm t`, you might attempt to set your makeprg to be:\n\n```\n:set makeprg=npm\\\\ t\n```\n\nIf you run:\n\n```\n:make\n```\n\nVim will execute `npm t`, but you will be staring at the frozen screen while your JavaScript test runs. With vim-dispatch, you can just run:\n\n```\n:Make\n```\n\nVim will run `npm t` asynchronously. This way, while `npm t` is running on a background process, you can continue doing whatever you were doing. Awesome!\n\n### Async Dispatch\n\nThe `:Dispatch` command is like the `:compiler` and the `:!` command. It can run any external command asynchronously in Vim.\n\nAssume that you are inside a ruby spec file and you need to run a test. Run:\n\n```\n:Dispatch bundle exec rspec %\n```\n\nVim will asynchronously run the `rspec` command against the current file (`%`).\n\n### Automating Dispatch\n\nVim-dispatch has `b:dispatch` buffer variable that you can configure to evaluate specific command automatically. You can leverage it with `autocmd`. If you add this in your vimrc:\n\n```\nautocmd BufEnter *_spec.rb let b:dispatch = 'bundle exec rspec %'\n```\n\nNow each time you enter a file (`BufEnter`) that ends with `_spec.rb`, running `:Dispatch` automatically executes `bundle exec rspec {your-current-ruby-spec-file}`.\n\n## Learn Compile the Smart Way\n\nIn this chapter, you learned that you can use the `make` and `compiler` commands to run *any* process from inside Vim asynchronously to complement your programming workflow. Vim's ability to extend itself with other programs makes it powerful.\n\n\n## Link\n- Prev [Ch18. Git](./ch18_git.md)\n- Next [Ch20. Views, Sessions, and Viminfo](./ch20_views_sessions_viminfo.md)\n"
  },
  {
    "path": "ch20_views_sessions_viminfo.md",
    "content": "# Ch20. Views, Sessions, and Viminfo\n\nAfter you worked on a project for a while, you may find the project to gradually take shape with its own settings, folds, buffers, layouts, etc. It's like decorating your apartment after living in it for a while. The problem is, when you close Vim, you lose those changes. Wouldn't it be nice if you could keep those changes so the next time you open Vim, it looks just like you had never left?\n\nIn this chapter, you will learn how to use View, Session, and Viminfo to preserve a \"snapshot\" of your projects.\n\n## View\n\nA View is the smallest subset of the three (View, Session, Viminfo). It is a collection of settings for one window. If you spend a long time working on a window and you want to preserve the maps and folds, you can use a View.\n\nLet's create a file called `foo.txt`:\n\n```\nfoo1\nfoo2\nfoo3\nfoo4\nfoo5\nfoo6\nfoo7\nfoo8\nfoo9\nfoo10\n```\n\nIn this file, create three changes:\n1. On line 1, create a manual fold `zf4j` (fold the next 4 lines).\n2. Change the `number` setting: `setlocal nonumber norelativenumber`. This will remove the number indicators on the left side of the window.\n3. Create a local mapping to go down two lines each time you press `j` instead of one: `:nnoremap <buffer> j jj`.\n\nYour file should look like this:\n\n```\n+-- 5 lines: foo1 -----\nfoo6\nfoo7\nfoo8\nfoo9\nfoo10\n```\n\n### Configuring View Attributes\n\nRun:\n\n```\n:set viewoptions?\n```\n\nBy default it should say (yours may look different depending on your vimrc):\n\n```\nviewoptions=folds,cursor,curdir\n```\n\nLet's configure `viewoptions`. The three attributes you want to preserve are the folds, the maps, and the local set options. If your setting looks like mine, you already have the `folds` option. You need to tell View to remember the `localoptions`. Run:\n\n```\n:set viewoptions+=localoptions\n```\n\nTo learn what other options are available for `viewoptions`, check out `:h viewoptions`. Now if you run `:set viewoptions?`, you should see:\n\n```\nviewoptions=folds,cursor,curdir,localoptions\n```\n\n### Saving the View\n\nWith the `foo.txt` window properly folded and having `nonumber norelativenumber` options, let's save the View. Run:\n\n```\n:mkview\n```\n\nVim creates a View file.\n\n### View Files\n\nYou might wonder, \"Where did Vim save this View file?\" To see where Vim saves it, run:\n\n```\n:set viewdir?\n```\n\nIn Unix based OS the default should say `~/.vim/view` (if you have a different OS, it might show a different path. Check out `:h viewdir` for more). If you are running a Unix based OS and want to change it to a different path, add this into your vimrc:\n\n```\nset viewdir=$HOME/else/where\n```\n\n### Loading the View File\n\nClose the `foo.txt` if you haven't, then open `foo.txt` again. **You should see the original text without the changes.** That's expected. \n\nTo restore the state, you need to load the View file. Run:\n\n```\n:loadview\n```\n\nNow you should see:\n\n```\n+-- 5 lines: foo1 -----\nfoo6\nfoo7\nfoo8\nfoo9\nfoo10\n```\n\nThe folds, local settings, and local mappings are restored. If you notice, your cursor should also be on the line where you left it when you ran `:mkview`. As long as you have the `cursor` option, View also remembers your cursor position.\n\n### Multiple Views\n\nVim lets you save 9 numbered Views (1-9).\n\nSuppose you want to make an additional fold (say you want to fold the last two lines) with `:9,10 fold`. Let's save this as View 1. Run:\n\n```\n:mkview 1\n```\n\nIf you want to make one more fold with `:6,7 fold` and save it as a different View, run:\n\n```\n:mkview 2\n```\n\nClose the file. When you open `foo.txt` and you want to load View 1, run:\n\n```\n:loadview 1\n```\n\nTo load View 2, run:\n\n```\n:loadview 2\n```\n\nTo load the original View, run:\n\n```\n:loadview\n```\n\n### Automating View Creation\n\nOne of the worst things that can happen is, after spending countless hours organizing a large file with folds, you accidentally close the window and lose all fold information. To prevent this, you might want to automatically create a View each time you close a buffer. Add this in your vimrc:\n\n```\nautocmd BufWinLeave *.txt mkview\n```\n\nAdditionally, it might be nice to load View when you open a buffer:\n\n```\nautocmd BufWinEnter *.txt silent loadview\n```\n\nNow you don't have to worry about creating and loading View anymore when you are working with `txt` files. Keep in mind that over time, your `~/.vim/view` might start to accumulate View files. It's good to clean it up once every few months.\n\n## Sessions\n\nIf a View saves the settings of a window, a Session saves the information of all windows (including the layout).\n\n### Creating a New Session\n\nSuppose you are working with these 3 files in a `foobarbaz` project:\n\nInside `foo.txt`:\n\n```\nfoo1\nfoo2\nfoo3\nfoo4\nfoo5\nfoo6\nfoo7\nfoo8\nfoo9\nfoo10\n```\n\nInside `bar.txt`:\n\n```\nbar1\nbar2\nbar3\nbar4\nbar5\nbar6\nbar7\nbar8\nbar9\nbar10\n```\n\nInside `baz.txt`:\n\n```\nbaz1\nbaz2\nbaz3\nbaz4\nbaz5\nbaz6\nbaz7\nbaz8\nbaz9\nbaz10\n```\n\nNow let's say that you split your windows with `:split` and `:vsplit`. To preserve this look, you need to save the Session. Run:\n\n```\n:mksession\n```\n\nUnlike `mkview` where it saves to `~/.vim/view` by default, `mksession` saves a Session file (`Session.vim`) in the current directory. Check out the file if you're curious what's inside.\n\nIf you want to save the Session file somewhere else, you can pass an argument to `mksession`:\n\n```\n:mksession ~/some/where/else.vim\n```\n\nIf you want to overwrite the existing Session file, call the command with a `!` (`:mksession! ~/some/where/else.vim`).\n\n### Loading a Session\n\nTo load a Session, run:\n\n```\n:source Session.vim\n```\n\nNow Vim looks like just the way you left it, including the split windows! Alternatively, you can also load a Session file from the terminal:\n\n```\nvim -S Session.vim\n```\n\n### Configuring Session Attributes\n\nYou can configure the attributes Session saves. To see what is currently being saved, run:\n\n```\n:set sessionoptions?\n```\n\nMine says:\n\n```\nblank,buffers,curdir,folds,help,tabpages,winsize,terminal\n```\n\nIf you don't want to save `terminal` when you save a Session, remove it from the session options. Run:\n\n```\n:set sessionoptions-=terminal\n```\n\nIf you want to add an `options` when you save a Session, run:\n\n```\n:set sessionoptions+=options\n```\n\nHere are some attributes that `sessionoptions` can store:\n- `blank` stores empty windows\n- `buffers` stores buffers\n- `folds` stores folds\n- `globals` stores global variables (must start with an uppercase letter and contain at least one lowercase letter)\n- `options` stores options and mappings\n- `resize` stores window lines and columns\n- `winpos` stores window position\n- `winsize` stores window sizes\n- `tabpages` stores tabs\n- `unix` stores files in Unix format\n\nFor the complete list check out `:h 'sessionoptions'`.\n\nSession is a useful tool to preserve your project's external attributes. However, some internal attributes aren't saved by Session, like local marks, registers, histories, etc. To save them, you need to use Viminfo!\n\n## Viminfo\n\nIf you notice, after yanking a word into register a and quitting Vim, the next time you open Vim you still have that text stored in register a. This is actually a work of Viminfo. Without it, Vim won't remember the register after you close Vim.\n\nIf you use Vim 8 or higher, Vim enables Viminfo by default, so you may have been using Viminfo this whole time without knowing it!\n\nYou might ask: \"What does Viminfo save? How does it differ from Session?\"\n\nTo use Viminfo, first you need to have `+viminfo` feature available (`:version`). Viminfo stores:\n- The command-line history.\n- The search string history.\n- The input-line history.\n- Contents of non-empty registers.\n- Marks for several files.\n- File marks, pointing to locations in files.\n- Last search / substitute pattern (for 'n' and '&').\n- The buffer list.\n- Global variables.\n\nIn general, Session stores the \"external\" attributes and Viminfo the \"internal\" attributes.\n\nUnlike Session where you can have one Session file per project, you normally will use one Viminfo file per computer. Viminfo is project-agnostic.\n\nThe default Viminfo location for Unix is `$HOME/.viminfo` (`~/.viminfo`). If you use a different OS, your Viminfo location might be different. Check out `:h viminfo-file-name`. Each time you make \"internal\" changes, like yanking a text into a register, Vim automatically updates the Viminfo file.\n\n*Make sure that you have `nocompatible` option set (`set nocompatible`), otherwise your Viminfo will not work.*\n\n### Writing and Reading Viminfo\n\nAlthough you will use only one Viminfo file, you can create multiple Viminfo files. To write a Viminfo file, use the `:wviminfo` command (`:wv` for short).\n\n```\n:wv ~/.viminfo_extra\n```\n\nTo overwrite an existing Viminfo file, add a bang to the `wv` command:\n\n```\n:wv! ~/.viminfo_extra\n```\n\nBy default Vim will read from `~/.viminfo` file. To read from a different Viminfo file, run `:rviminfo`, or `:rv` for short:\n\n```\n:rv ~/.viminfo_extra\n```\n\nTo start Vim with a different Viminfo file from the terminal, use the `i` flag:\n\n```\nvim -i viminfo_extra\n```\n\nIf you use Vim for different tasks, like coding and writing, you can create a Viminfo optimized for writing and another for coding.\n\n```\nvim -i viminfo_writing\n\nvim -i viminfo_coding\n```\n\n### Starting Vim Without Viminfo\n\nTo start Vim without Viminfo, you can run from the terminal:\n\n```\nvim -i NONE\n```\n\nTo make it permanent, you can add this in your vimrc file:\n\n```\nset viminfo=\"NONE\"\n```\n\n### Configuring Viminfo Attributes\n\nSimilar to `viewoptions` and `sessionoptions`, you can instruct what attributes to save with the `viminfo` option. Run:\n\n```\n:set viminfo?\n```\n\nYou will get:\n\n```\n!,'100,<50,s10,h\n```\n\nThis looks cryptic. Let's break it down:\n- `!` saves global variables that start with an uppercase letter and don't contain lowercase letters. Recall that `g:` indicates a global variable. For example, if at some point you wrote the assignment `let g:FOO = \"foo\"`, Viminfo will save the global variable `FOO`. However if you did `let g:Foo = \"foo\"`, Viminfo will not save this global variable because it contains lowercase letters. Without `!`, Vim won't save those global variables.\n- `'100` represents marks. In this case, Viminfo will save the local marks (a-z) of the last 100 files. Be aware that if you tell Viminfo to save too many files, Vim can start slowing down. 1000 is a good number to have.\n- `<50` tells Viminfo how many maximum lines are saved for each register (50 in this case). If I yank 100 lines of text into register a (`\"ay99j`) and close Vim, the next time I open Vim and paste from register a (`\"ap`), Vim will only paste 50 lines max. If you don't give maximum line number, *all* lines will be saved. If you give it 0, nothing will be saved.\n- `s10` sets a size limit (in kb) for a register. In this case, any register greater than 10kb size will be excluded.\n- `h` disables highlighting (from `hlsearch`) when Vim starts.\n\nThere are other options that you can pass. To learn more, check out `:h 'viminfo'`.\n\n## Using Views, Sessions, and Viminfo the Smart Way\n\nVim has View, Session, and Viminfo to take different levels of your Vim environment snapshots. For micro projects, use Views. For larger projects, use Sessions. You should take your time to check out all the options that View, Session, and Viminfo offers.\n\nCreate your own View, Session, and Viminfo for your own editing style. If you ever need to use Vim outside of your computer, you can just load your settings and you will immediately feel at home!\n\n## Link\n- Prev [Ch19. Compile](./ch19_compile.md)\n- Next [Ch21. Multiple File Operations](./ch21_multiple_file_operations.md)\n"
  },
  {
    "path": "ch21_multiple_file_operations.md",
    "content": "# Ch21. Multiple File Operations\n\nBeing able to update in multiple files is another useful editing tool to have. Earlier you learned how to update multiple texts with `cfdo`. In this chapter, you will learn the different ways you can edit multiple files in Vim.\n\n## Different Ways to Execute a Command in Multiple Files\n\nVim has eight ways to execute commands across multiple files:\n- arg list (`argdo`)\n- buffer list (`bufdo`)\n- window list (`windo`)\n- tab list (`tabdo`)\n- quickfix list (`cdo`)\n- quickfix list filewise (`cfdo`)\n- location list (`ldo`)\n- location list filewise (`lfdo`)\n\nPractically speaking, you will probably only use one or two most of the time (I personally use `cdo` and `argdo` more than others), but it's good to learn about all the available options and use the ones that match your editing style. \n\nLearning eight commands might sound daunting. But in reality, these commands work similarly. After learning one, learning the rest will get easier. They all share the same big idea: make a list of their respective categories then pass them the command that you want to run.\n\n## Argument List\n\nThe argument list is the most basic list. It creates a list of files. To create a list of file1, file2, and file3, you can run:\n\n```\n:args file1 file2 file3\n```\n\nYou can also pass it a wildcard (`*`), so if you want to make a list of all `.js` files in the current directory, run:\n\n```\n:args *.js\n```\n\nIf you want to make a list of all Javascript files that start with \"a\" in the current directory, run:\n\n```\n:args a*.js\n```\n\nThe wildcard matches one or more of any filename character in the current directory, but what if you need to search recursively in any directory? You can use the double wildcard (`**`). To get all Javascript files inside the directories within your current location, run:\n\n```\n:args **/*.js\n```\n\nOnce you run the `args` command, your current buffer will be switched to the first item on the list. To view the list of files you just created, run `:args`. Once you've created your list, you can traverse them. `:first` will put you on the first item on the list. `:last` will put you on the last list. To move the list forward one file at a time, run `:next`. To move the list backward one file at a time, run `:prev`. To move forward / backward one file at a time and save the changes, run `:wnext` and `:wprev`. There are plenty more navigation commands. Check out `:h arglist` for more.\n\nThe arg list is useful if you need to target a specific type of file or a few files. Maybe you need to update all the \"donut\" into \"pancake\" inside all `yml` files, you can do:\n\n```\n:args **/*.yml\n:argdo %s/donut/pancake/g | update\n\n```\nIf you run the `args` command again, it will replace the previous list. For example, if you previously ran:\n\n```\n:args file1 file2 file3\n```\n\nAssuming these files exist, you now have a list of `file1`, `file2`, and `file3`. Then you run this:\n\n```\n:args file4 file5\n```\n\nYour initial list of `file1`, `file2`, and `file3` is replaced with `file4` and `file5`. If you have `file1`, `file2`, and `file3` in your arg list and you want to *add* `file4` and `file5` into your initial files list, use the `:arga` command. Run:\n\n```\n:arga file4 file5\n```\n\nNow you have `file1`, `file2`, `file3`, `file4`, and `file5` in your arg list.\n\nIf you run `:arga` without any argument, Vim will add your current buffer into the current arg list. If you already have `file1`, `file2`, and `file3` in your arg list and your current buffer is on `file5`, running `:arga` adds `file5` into the list.\n\nOnce you have the list, you can pass it with any command-line commands of your choosing. You've seen it being done with substitution (`:argdo %s/donut/pancake/g`). Some other examples:\n- To delete all lines that contain \"dessert\" across the arg list, run `:argdo g/dessert/d`.\n- To execute macro a (assuming you have recorded something in macro a) across the arg list, run `:argdo norm @a`.\n- To write \"hello \" followed by the filename on the first line, run `:argdo 0put='hello ' .. @:`.\n\nOnce you're done, don't forget to save them with `:update`.\n\nSometimes you need to run the commands only on the first n items of the argument list. If that's the case, just pass to the `argdo` command an address. For example, to run the substitute command only on the first 3 items from the list, run `:1,3argdo %s/donut/pancake/g`.\n\n## Buffer List\n\nThe buffer list will be organically created when you edit new files because each time you create a new file / open a file, Vim saves it in a buffer (unless you explicitly delete it). So if you already opened 3 files: `file1.rb file2.rb file3.rb`, you already have 3 items in your buffer list. To display the buffer list, run `:buffers` (alternatively: `:ls` or `:files`). To traverse forward and backward, use `:bnext` and `:bprev`. To go to the first and last buffer from the list, use `:bfirst` and `:blast` (having a blast yet? :D).\n\nBy the way, here's a cool buffer trick unrelated to this chapter: if you have a number of items in your buffer list, you can show all of them with `:ball` (buffer all). The `ball` command displays all buffers horizontally. To display them vertically, run `:vertical ball`.\n\nBack to the topic, the mechanics to run operation across all buffers is similar to the arg list. Once you have created your buffer list, you just need to prepend the command(s) that you want to run with `:bufdo` instead of `:argdo`. So if you want to substitute all \"donut\" with \"pancake\" across all buffers then save the changes, run `:bufdo %s/donut/pancake/g | update`.\n\n## Window and Tab List\n\nThe windows and tabs list are also similar to the arg and buffer list. The only differences are their context and syntax. \n\nWindow operations are performed on each open window and performed with `:windo`. Tab operations are performed on each tab you have opened and performed with `:tabdo`. For more, check out `:h list-repeat`, `:h :windo`, and `:h :tabdo`.\n\nFor example, if you have three windows opened (you can open new windows with `Ctrl-W v` for a vertical window and `Ctrl-W s` for a horizontal window) and you run `:windo 0put ='hello' . @%`, Vim will output \"hello\" + filename to all open windows.\n\n## Quickfix List\n\nIn the previous chapters (Ch3 and Ch19), I have spoken about quickfixes. Quickfix has many uses. Many popular plugins use quickfixes, so it's good to spend more time to understand them.\n\nIf you're new to Vim, quickfix might be a new concept. Back in the old days when you actually have to explicitly compile your code, during the compilation phase you would encounter errors. To display these errors, you need a special window. That's where quickfix comes in. When you compile your code, Vim displays error messages in the quickfix window so you can fix them later. Many modern languages don't require an explicit compile anymore, but that doesn't make quickfix obsolete. Nowadays, people use quickfix for all sorts of things, like displaying a virtual terminal output and storing search results. Let's focus on the latter one, storing search results.\n\nIn addition to the compile commands, certain Vim commands rely on quickfix interfaces. One type of command that use quickfixes heavily are the search commands. Both `:vimgrep` and `:grep` use quickfixes by default.\n\nFor example, if you need to search for \"donut\" in all Javascript files recursively, you can run:\n\n```\n:vimgrep /donut/ **/*.js\n```\n\nThe result for the \"donut\" search is stored in the quickfix window. To see these match results' quickfix window, run:\n\n```\n:copen\n```\n\nTo close it, run:\n\n```\n:cclose\n```\n\nTo traverse the quickfix list forward and backward, run:\n\n```\n:cnext\n:cprev\n```\n\nTo go to the first and the last item in the match, run:\n\n```\n:cfirst\n:clast\n```\n\nEarlier I mentioned that there were two quickfix commands: `cdo` and `cfdo`. How do they differ? `cdo` executes command for each item in the quickfix list while `cfdo` executes command for each *file* in the quickfix list.\n\nLet me clarify. Suppose that after running the `vimgrep` command above, you found:\n- 1 result in `file1.js`\n- 10 results in `file2.js`\n\nIf you run `:cfdo %s/donut/pancake/g`, this will effectively run `%s/donut/pancake/g` once in `file1.js` and once in `file2.js`. It runs *as many times as there are files in the match.* Since there are two files in the results, Vim executes the substitute command once on `file1.js` and once more on `file2.js`, despite the fact that there are 10 matches in the second file. `cfdo` only cares about how many total files are in the quickfix list.\n\nIf you run `:cdo %s/donut/pancake/g`, this will effectively run `%s/donut/pancake/g` once in `file1.js` and *ten times* in `file2.js`. It runs as many times as there are actual items in the quickfix list. Since there is only one match found in `file1.js` and 10 matches found in `file2.js`, it will run a total of 11 times.\n\nSince you ran `%s/donut/pancake/g`, it would make sense to use `cfdo`. It did not make sense to use `cdo` because it would run `%s/donut/pancake/g` ten times in `file2.js` (`%s` is a file-wide substitution). Running `%s` once per file is enough. If you used `cdo`, it would make more sense to pass it with `s/donut/pancake/g` instead.\n\nWhen deciding whether to use `cfdo` or `cdo`, think of the command scope that you are passing it to. Is this a file-wide command (like `:%s` or `:g`) or is this a line-wise command (like `:s` or `:!`)?\n\n## Location List\n\nLocation list is similar to quickfix list in a sense that Vim also uses a special window to display messages. The difference between a quickfix list and a location list is that at any time, you may only have one quickfix list, whereas you can have as many location lists as windows.\n\nSuppose that you have two windows opened, one window displaying `food.txt` and another displaying `drinks.txt`. From inside `food.txt`, you run a location-list search command `:lvimgrep` (the location variant for the `:vimgrep` command):\n\n```\n:lvim /bagel/ **/*.md\n```\n\nVim will create a location list of all the bagel search matches for that `food.txt` *window*. You can see the location list with `:lopen`. Now go to the other window `drinks.txt` and run:\n\n```\n:lvimgrep /milk/ **/*.md\n```\n\nVim will create a *separate* location list with all the milk search results for that `drinks.txt` *window*.\n\nFor each location-command you run in each window, Vim creates a distinct location list. If you have 10 different windows, you can have up to 10 different location lists. Contrast this with the quickfix list where you can only have one at any time. If you have 10 different windows, you still get only one quickfix list.\n\nMost of the location list commands are similar to quickfix commands except that they are prefixed with `l-` instead. For example: `:lvimgrep`, `:lgrep`, and `:lmake` vs `:vimgrep`, `:grep`, and `:make`. To manipulate the location list window, again, the commands look similar to the quickfix commands `:lopen`, `:lclose`, `:lfirst`, `:llast`, `:lnext`, and `:lprev` vs `:copen`, `:cclose`, `:cfirst`, `:clast`, `:cnext`, and `:cprev`.\n\nThe two location list multi-file commands are also similar to quickfix multi-file commands: `:ldo` and `:lfdo`. `:ldo` executes the location command in each location list while `:lfdo` executes the location list command for each file in the location list. For more, check out `:h location-list`.\n\n## Running Multiple-File Operations in Vim\n\nKnowing how to do a multiple file operation is a useful skill to have in editing. Whenever you need to change a variable name across multiple files, you want to execute them in one swoop. Vim has eight different ways you can do this.\n\nPractically speaking, you probably won't use all eight equally. You will gravitate towards one or two. When you are starting out, pick one (I personally suggest starting with the arg list `:argdo`) and master it. Once you are comfortable with one, then learn the next one. You will find that learning the second, third, fourth gets easier. Be creative. Use it with different combinations. Keep practicing until you can do this effortlessly and without much thinking. Make it part of your muscle memory.\n\nWith that being said, you've mastered Vim editing. Congratulations!\n\n## Link\n- Prev [Ch20. Views, Sessions, and Viminfo](./ch20_views_sessions_viminfo.md)\n- Next [Ch22. Vimrc](./ch22_vimrc.md)\n"
  },
  {
    "path": "ch22_vimrc.md",
    "content": "# Ch22. Vimrc\n\nIn the previous chapters, you learned how to use Vim. In this chapter, you will learn how to organize and configure vimrc. \n\n## How Vim Finds Vimrc\n\nThe conventional wisdom for vimrc is to add a `.vimrc` dotfile in the home directory `~/.vimrc` (it might be different depending on your OS).\n\nBehind the scene, Vim looks at multiple places for a vimrc file. Here are the places that Vim checks:\n- `$VIMINIT`\n- `$HOME/.vimrc`\n- `$HOME/.vim/vimrc`\n- `$EXINIT`\n- `$HOME/.exrc`\n- `$VIMRUNTIME/defaults.vim`\n\nWhen you start Vim, it will check the above six locations in that order for a vimrc file. The first found vimrc file will be used and the rest is ignored. \n\nFirst Vim will look for a `$VIMINIT`. If there is nothing there, Vim will check for `$HOME/.vimrc`. If there is nothing there, Vim will check for `$HOME/.vim/vimrc`. If Vim finds it, it will stop looking and use `$HOME/.vim/vimrc`. \n\nThe first location, `$VIMINIT`, is an environment variable. By default it is undefined. If you want to use `~/dotfiles/testvimrc` as your `$VIMINIT` value, you can create an environment variable containing the path of that vimrc. After you run `export VIMINIT='let $MYVIMRC=\"$HOME/dotfiles/testvimrc\" | source $MYVIMRC'`, Vim will now use `~/dotfiles/testvimrc` as your vimrc file.\n\nThe second location, `$HOME/.vimrc`, is the conventional path for many Vim users. `$HOME` in many cases is your home directory (`~`). If you have a `~/.vimrc` file, Vim will use this as your vimrc file.\n\nThe third, `$HOME/.vim/vimrc`, is located inside the `~/.vim` directory. You might have the `~/.vim` directory already for your plugins, custom scripts, or View files. Note that there is no dot in vimrc file name (`$HOME/.vim/.vimrc` won't work, but `$HOME/.vim/vimrc` will).\n\nThe fourth, `$EXINIT` works similar to `$VIMINIT`. \n\nThe fifth, `$HOME/.exrc` works similar to `$HOME/.vimrc`.\n\nThe sixth, `$VIMRUNTIME/defaults.vim` is the default vimrc that comes with your Vim build. In my case, I have Vim 8.2 installed using Homebrew, so my path is (`/usr/local/share/vim/vim82`). If Vim does not find any of the previous six vimrc files, it will use this file.\n\nFor the remaining of this chapter, I am assuming that the vimrc uses the `~/.vimrc` path. \n\n## What to Put in My Vimrc?\n\nA question I asked when I started was, \"What should I put in my vimrc?\"\n\nThe answer is, \"anything you want\". The temptation to copy-paste other people's vimrc is real, but you should resist it. If you insist to use someone else's vimrc, make sure that you know what it does, why and how s/he uses it, and most importantly, if it is relevant to you. Just because someone uses it doesn't mean you'll use it too.\n\n## Basic Vimrc Content\n\nIn the nutshell, a vimrc is a collection of:\n- Plugins\n- Settings\n- Custom Functions\n- Custom Commands\n- Mappings\n\nThere are other things not mentioned above, but in general, this covers most use cases.\n\n### Plugins\n\nIn the previous chapters, I have mentioned different plugins, like [fzf.vim](https://github.com/junegunn/fzf.vim), [vim-mundo](https://github.com/simnalamburt/vim-mundo), and [vim-fugitive](https://github.com/tpope/vim-fugitive).\n\nTen years ago, managing plugins was a nightmare. However, with the rise of modern plugin managers, installing plugins can now be done in seconds. I am currently using [vim-plug](https://github.com/junegunn/vim-plug) as my plugin manager, so I will use it in this section. The concept should be similar with other popular plugin managers. I would strongly recommend you to check out different ones, such as:\n- [vundle.vim](https://github.com/VundleVim/Vundle.vim)\n- [vim-pathogen](https://github.com/tpope/vim-pathogen)\n- [dein.vim](https://github.com/Shougo/dein.vim)\n\nThere are more plugin managers than the ones listed above, feel free to look around. To install vim-plug, if you have a Unix machine, run:\n\n```\ncurl -fLo ~/.vim/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim\n```\n\nTo add new plugins, drop your plugin names (`Plug 'github-username/repository-name'`) between the `call plug#begin()` and the `call plug#end()` lines. So if you want to install `emmet-vim` and `nerdtree`, put the following snippet down in your vimrc:\n\n```\ncall plug#begin('~/.vim/plugged')\n  Plug 'mattn/emmet-vim'\n  Plug 'preservim/nerdtree'\ncall plug#end()\n```\n\nSave the changes, source it (`:source %`), and run `:PlugInstall` to install them.\n\nIn the future if you need to remove unused plugins, you just need to remove the plugin names from the `call` block, save and source, and run the `:PlugClean` command to remove it from your machine.\n\nVim 8 has its own built-in package managers. You can check out `:h packages` for more information. In the next chapter, I will show you how to use it.\n\n### Settings\n\nIt is common to see a lot of `set` options in any vimrc. If you run the set command from the command-line mode, it is not permanent. You will lose it when you close Vim. For example, instead of running `:set relativenumber number` from the Command-line mode each time you run Vim, you could just put these inside vimrc:\n\n```\nset relativenumber number\n```\n\nSome settings require you to pass it a value, like `set tabstop=2`. Check out the help page for each setting to learn what kind of values it accepts.\n\nYou can also use a `let` instead of `set` (make sure to prepend it with `&`). With `let`, you can use an expression as a value. For example, to set the `'dictionary'` option to a path only if the path exists:\n\n```\nlet s:english_dict = \"/usr/share/dict/words\"\n\nif filereadable(s:english_dict)\n  let &dictionary=s:english_dict\nendif\n```\n\nYou will learn about Vimscript assignments and conditionals in later chapters. \n\nFor a list of all possible options in Vim, check out `:h E355`.\n\n### Custom Functions\n\nVimrc is a good place for custom functions. You will learn how to write your own Vimscript functions in a later chapter.\n\n### Custom Commands\n\nYou can create a custom command-line command with `command`.\n\nTo create a basic command `GimmeDate` to display today's date:\n\n```\n:command! GimmeDate echo call(\"strftime\", [\"%F\"])\n```\n\nWhen you run `:GimmeDate`, Vim will display a date like \"2021-01-1\".\n\nTo create a basic command with an input, you can use `<args>`. If you want to pass to `GimmeDate` a specific time/date format:\n\n```\n:command! GimmeDate echo call(\"strftime\", [<args>])\n\n:GimmeDate \"%F\"\n\" 2020-01-01\n\n:GimmeDate \"%H:%M\"\n\" 11:30\n```\n\nIf you want to restrict the number of arguments, you can pass it `-nargs` flag. Use `-nargs=0` to pass no argument, `-nargs=1` to pass one argument, `-nargs=+` to pass at least one argument, `-nargs=*` to pass any number of arguments, and `-nargs=?` to pass 0 or one arguments. If you want to pass nth argument, use `-nargs=n` (where `n` is any integer).\n\n`<args>` has two variants: `<f-args>` and `<q-args>`. The former is used to pass arguments to Vimscript functions. The latter is used to automatically convert user input to strings.\n\nUsing `args`:\n\n```\n:command! -nargs=1 Hello echo \"Hello \" . <args>\n:Hello \"Iggy\"\n\" returns 'Hello Iggy'\n\n:Hello Iggy\n\" Undefined variable error\n```\n\nUsing `q-args`:\n\n```\n:command! -nargs=1 Hello echo \"Hello \" . <q-args>\n:Hello Iggy\n\" returns 'Hello Iggy'\n```\n\nUsing `f-args`:\n\n```\n:function! PrintHello(person1, person2)\n:  echo \"Hello \" . a:person1 . \" and \" . a:person2\n:endfunction\n\n:command! -nargs=* Hello call PrintHello(<f-args>)\n\n:Hello Iggy1 Iggy2\n\" returns \"Hello Iggy1 and Iggy2\"\n```\n\nThe functions above will make a lot more sense once you get to the Vimscript functions chapter. \n\nTo learn more about command and args, check out `:h command` and `:args`.\n\n### Maps\n\nIf you find yourself repeatedly performing the same complex task, it is a good indicator that you should create a mapping for that task.\n\nFor example, I have these two mappings in my vimrc:\n\n```\nnnoremap <silent> <C-f> :GFiles<CR>\n\nnnoremap <Leader>tn :call ToggleNumber()<CR>\n```\n\nOn the first one, I map `Ctrl-F` to [fzf.vim](https://github.com/junegunn/fzf.vim) plugin's `:Gfiles` command (quickly search for Git files). On the second one, I map `<Leader>tn` to call a custom function `ToggleNumber` (toggles `norelativenumber` and `relativenumber` options). The `Ctrl-F` mapping overwrites Vim's native page scroll. Your mapping will overwrite Vim controls if they collide. Because I almost never used that feature, I decided that it is safe to overwrite it.\n\nBy the way, what is this \"leader\" key in `<Leader>tn`?\n\nVim has a leader key to help with mappings. For example, I mapped `<Leader>tn` to run the `ToggleNumber()` function. Without the leader key, I would be using `tn`, but Vim already has `t` (the \"till\" search navigation). With the leader key, I can now press the key assigned as a leader, then `tn` without interfering with existing commands. The leader key is a key that you can setup to start your mapping combo. By default Vim uses the backslash as the leader key (so `<Leader>tn` becomes \"backslash-t-n\").\n\nI personally like to use `<Space>` as the leader key instead of the backslash default. To change your leader key, add this in your vimrc:\n\n```\nlet mapleader = \"\\<space>\"\n```\n\nThe `nnoremap` command used above can be broken down into three parts:\n- `n` represents the normal mode.\n- `nore` means non-recursive.\n- `map` is the map command.\n\nAt minimum, you could have used `nmap` instead of `nnoremap` (`nmap <silent> <C-f> :Gfiles<CR>`). However, it is a good practice to use the non-recursive variant to avoid potential infinite loop.\n\nHere's what could happen if you don't map non-recursively. Suppose you want to add a mapping to `B` to add a semi-colon at the end of the line, then go back one WORD (recall that `B` in Vim is a normal-mode navigation key to go backward one WORD).\n\n```\nnmap B A;<esc>B\n```\n\nWhen you press `B`... oh no! Vim adds `;` uncontrollably (interrupt it with `Ctrl-C`). Why did that happen? Because in the mapping `A;<esc>B`, the `B` does not refer to Vim's native `B` function (go back one WORD), but it refers to the mapped function. What you have is actually this:\n\n```\nA;<esc>A;<esc>A;<esc>A;<esc>...\n```\n\nTo solve this problem, you need to add a non-recursive map:\n\n```\nnnoremap B A;<esc>B\n```\n\nNow try calling `B` again. This time it successfully adds a `;` at the end of the line and go back one WORD. The `B` in this mapping represents Vim's original `B` functionality.\n\nVim has different maps for different modes. If you want to create a map for insert mode to exit insert mode when you press `jk`:\n\n```\ninoremap jk <esc>\n```\n\nThe other map modes are: `map` (Normal, Visual, Select, and Operator-pending), `vmap` (Visual and Select), `smap` (Select), `xmap` (Visual), `omap` (Operator-pending), `map!` (Insert and Command-line), `lmap` (Insert, Command-line, Lang-arg), `cmap` (Command-line), and `tmap` (terminal-job). I won't cover them in detail. To learn more, check out `:h map.txt`.\n\nCreate a map that's most intuitive, consistent, and easy-to-remember.\n\n## Organizing Vimrc\n\nOver time, your vimrc will grow large and become convoluted. There are two ways to keep your vimrc to look clean:\n- Split your vimrc into several files.\n- Fold your vimrc file.\n\n### Splitting Your Vimrc\n\nYou can split your vimrc to multiple files using Vim's `source` command. This command reads command-line commands from the given file argument.\n\nLet's create a file inside the `~/.vim` directory and name it `/settings` (`~/.vim/settings`). The name itself is arbitrary and you can name it whatever you like.\n\nYou are going to split it into four components:\n- Third-party plugins (`~/.vim/settings/plugins.vim`).\n- General settings (`~/.vim/settings/configs.vim`).\n- Custom functions (`~/.vim/settings/functions.vim`).\n- Key mappings (`~/.vim/settings/mappings.vim`) .\n\nInside `~/.vimrc`:\n\n```\nsource $HOME/.vim/settings/plugins.vim\nsource $HOME/.vim/settings/configs.vim\nsource $HOME/.vim/settings/functions.vim\nsource $HOME/.vim/settings/mappings.vim\n```\n\nYou can edit these files by putting your cursor under the path and press `gf`.\n\nInside `~/.vim/settings/plugins.vim`:\n\n```\ncall plug#begin('~/.vim/plugged')\n  Plug 'mattn/emmet-vim'\n  Plug 'preservim/nerdtree'\ncall plug#end()\n```\n\nInside `~/.vim/settings/configs.vim`:\n\n```\nset nocompatible\nset relativenumber\nset number\n```\n\nInside `~/.vim/settings/functions.vim`:\n\n```\nfunction! ToggleNumber()\n  if(&relativenumber == 1)\n    set norelativenumber\n  else\n    set relativenumber\n  endif\nendfunc\n```\n\nInside `~/.vim/settings/mappings.vim`:\n\n```\ninoremap jk <esc>\nnnoremap <silent> <C-f> :GFiles<CR>\nnnoremap <Leader>tn :call ToggleNumber()<CR>\n```\n\nYour vimrc should work as usual, but now it is only four lines long!\n\nWith this setup, you easily know where to go. If you need to add more mappings, add them to the `/mappings.vim` file. In the future, you can always add more directories as your vimrc grows. For example, if you need to create a setting for your colorschemes, you can add a `~/.vim/settings/themes.vim`.\n\n### Keeping One Vimrc File\n\nIf you prefer to keep one vimrc file to keep it portable, you can use the marker folds to keep it organized. Add this at the top of your vimrc:\n\n```\n\" setup folds {{{\naugroup filetype_vim\n  autocmd!\n  autocmd FileType vim setlocal foldmethod=marker\naugroup END\n\" }}}\n```\n\nVim can detect what kind of filetype the current buffer has (`:set filetype?`). If it is a `vim` filetype, you can use a marker fold method. Recall that a marker fold uses `{{{` and `}}}` to indicate the starting and ending folds.\n\nAdd `{{{` and `}}}` folds to the rest of your vimrc (don't forget to comment them with `\"`):\n\n```\n\" setup folds {{{\naugroup filetype_vim\n  autocmd!\n  autocmd FileType vim setlocal foldmethod=marker\naugroup END\n\" }}}\n\n\" plugins {{{\ncall plug#begin('~/.vim/plugged')\n  Plug 'mattn/emmet-vim'\n  Plug 'preservim/nerdtree'\ncall plug#end()\n\" }}}\n\n\" configs {{{\nset nocompatible\nset relativenumber\nset number\n\" }}}\n\n\" functions {{{\nfunction! ToggleNumber()\n  if(&relativenumber == 1)\n    set norelativenumber\n  else\n    set relativenumber\n  endif\nendfunc\n\" }}}\n\n\" mappings {{{\ninoremap jk <esc>\nnnoremap <silent> <C-f> :GFiles<CR>\nnnoremap <Leader>tn :call ToggleNumber()<CR>\n\" }}}\n```\n\nYour vimrc should look like this:\n\n```\n+-- 6 lines: setup folds -----\n\n+-- 6 lines: plugins ---------\n\n+-- 5 lines: configs ---------\n\n+-- 9 lines: functions -------\n\n+-- 5 lines: mappings --------\n```\n\n## Running Vim With or Without Vimrc and Plugins\n\nIf you need to run Vim without both vimrc and plugins, run:\n\n```\nvim -u NONE\n```\n\nIf you need to launch Vim without vimrc but with plugins, run:\n\n```\nvim -u NORC\n```\n\nIf you need to run Vim with vimrc but without plugins, run:\n\n```\nvim --noplugin\n```\n\nIf you need to run Vim with a *different* vimrc, say `~/.vimrc-backup`, run:\n\n```\nvim -u ~/.vimrc-backup\n```\n\nIf you need to run Vim with only `defaults.vim` and without plugins, which is helpful to fix broken vimrc, run:\n\n```\nvim --clean\n```\n\n## Configure Vimrc the Smart Way\n\nVimrc is an important component of Vim customization. A good way to start building your vimrc is by reading other people's vimrcs and gradually build it over time. The best vimrc is not the one that developer X uses, but the one that is tailored exactly to fit your thinking framework and editing style.\n\n## Link\n- Prev [Ch21. Multiple File Operations](./ch21_multiple_file_operations.md)\n- Next [Ch23. Vim Packages](./ch23_vim_packages.md)\n"
  },
  {
    "path": "ch23_vim_packages.md",
    "content": "# Ch23. Vim Packages\n\nIn the previous chapter, I mentioned using an external plugin manager to install plugins. Since version 8, Vim comes with its own built-in plugin manager called *packages*. In this chapter, you will learn how to use Vim packages to install plugins.\n\nTo see if your Vim build has the ability to use packages, run `:version` and look for `+packages` attribute. Alternatively, you can also run `:echo has('packages')` (if it returns 1, then it has the packages ability).\n\n## Pack Directory\n\nCheck if you have a `~/.vim/` directory in the root path. If you don't, create one. Inside it, create a directory called `pack` (`~/.vim/pack/)`. Vim automatically knows to search inside this directory for packages.\n\n## Two Types of Loading\n\nVim package has two loading mechanisms: automatic and manual loading.\n\n### Automatic Loading\n\nTo load plugins automatically when Vim starts, you need to put them in the `start/` directory. The path looks like this:\n\n```\n~/.vim/pack/*/start/\n```\n\nNow you may ask, \"What is the `*` between `pack/` and `start/`?\" `*` is an arbitrary name and can be anything you want. let's name it `packdemo/`:\n\n```\n~/.vim/pack/packdemo/start/\n```\n\nKeep in mind that if you skip it and do something like this instead:\n\n```\n~/.vim/pack/start/\n```\n\nThe package system won't work. It is imperative to put a name between `pack/` and `start/`.\n\nFor this demo, let's try to install the [NERDTree](https://github.com/preservim/nerdtree) plugin. Go all the way to the `start/` directory (`cd ~/.vim/pack/packdemo/start/`) and clone the NERDTree repository:\n\n```\ngit clone https://github.com/preservim/nerdtree.git\n```\n\nThat's it! You are all set. The next time you start Vim, you can immediately execute NERDTree commands like `:NERDTreeToggle`.\n\nYou can clone as many plugin repositories as you want inside the `~/.vim/pack/*/start/` path. Vim will automatically load each one. If you remove the cloned repository (`rm -rf nerdtree/`), that plugin will not be available anymore.\n\n### Manual Loading\n\nTo load plugins manually when Vim starts, you need to put them in the `opt/` directory. Similar to automatic loading, the path looks like this:\n\n```\n~/.vim/pack/*/opt/\n```\n\nLet's use the same `packdemo/` directory from earlier:\n\n```\n~/.vim/pack/packdemo/opt/\n```\n\nThis time, let's install the [killersheep](https://github.com/vim/killersheep) game (this requires Vim 8.2). Go to the `opt/` directory (`cd ~/.vim/pack/packdemo/opt/`) and clone the repository:\n\n```\ngit clone https://github.com/vim/killersheep.git\n```\n\nStart Vim. The command to execute the game is `:KillKillKill`. Try running it. Vim will complain that it is not a valid editor command. You need to *manually* load the plugin first. Let's do that:\n\n```\n:packadd killersheep\n```\n\nNow try running the command again `:KillKillKill`. The command should work now.\n\nYou may wonder, \"Why would I ever want to manually load packages? Isn't it better to automatically load everything at the start?\"\n\nGreat question. Sometimes there are plugins that you won't use all the time, like that KillerSheep game. You probably don't need to load 10 different games and slow down Vim startup time. However, once in a while, when you are bored, you might want to play a few games. Use manual loading for nonessential plugins.\n\nYou can also use this to conditionally add plugins. Maybe you use both Neovim and Vim and there are plugins optimized for Neovim. You can add something like this in your vimrc:\n\n```\nif has('nvim')\n  packadd! neovim-only-plugin\nelse\n  packadd! generic-vim-plugin\nendif\n```\n\n## Organizing Packages\n\nRecall that the requirement to use Vim's package system is to have either:\n\n```\n~/.vim/pack/*/start/\n```\n\nOr:\n\n```\n~/.vim/pack/*/opt/\n```\n\nThe fact that `*` can be *any* name can be used to organize your packages. Suppose you want to group your plugins based on categories (colors, syntax, and games):\n\n```\n~/.vim/pack/colors/\n~/.vim/pack/syntax/\n~/.vim/pack/games/\n```\n\nYou can still use `start/` and `opt/` inside each of the directories.\n\n```\n~/.vim/pack/colors/start/\n~/.vim/pack/colors/opt/\n\n~/.vim/pack/syntax/start/\n~/.vim/pack/syntax/opt/\n\n~/.vim/pack/games/start/\n~/.vim/pack/games/opt/\n```\n\n## Adding Packages the Smart Way\n\nYou may wonder if Vim package will make popular plugin managers like vim-pathogen, vundle.vim, dein.vim, and vim-plug obsolete.\n\nThe answer is, as always, \"it depends\".\n\nI still use vim-plug because it makes it easy to add, remove or update plugins. If you use many plugins, it may be more convenient to use plugin managers because it is easy to update many simultaneously. Some plugin managers also offer asynchronous functionalities.\n\nIf you are a minimalist, try out Vim packages. If you are a heavy plugin user, you may want to consider using a plugin manager.\n\n## Link\n- Prev [Ch22. Vimrc](./ch22_vimrc.md)\n- Next [Ch24. Vim Runtime](./ch24_vim_runtime.md)\n"
  },
  {
    "path": "ch24_vim_runtime.md",
    "content": "# Ch24. Vim Runtime\n\nIn the previous chapters, I mentioned that Vim automatically looks for special paths like `pack/` (Ch. 22) and `compiler/` (Ch. 19) inside the `~/.vim/` directory. These are examples of Vim runtime paths.\n\nVim has more runtime paths than these two. In this chapter, you will learn a high-level overview of these runtime paths. The goal of this chapter is to show you when they are called. Knowing this will allow you to understand and customize Vim further.\n\n## Runtime Path\n\nIn a Unix machine, one of your Vim runtime paths is `$HOME/.vim/` (if you have a different OS like Windows, your path might be different). To see what the runtime paths for different OS are, check out `:h 'runtimepath'`. In this chapter, I will use `~/.vim/` as the default runtime path.\n\n## Plugin Scripts\n\nVim has a plugin runtime path that executes any scripts in this directory once each time Vim starts. Do not confuse the name \"plugin\" with Vim external plugins (like NERDTree, fzf.vim, etc).\n\nGo to `~/.vim/` directory and create a `plugin/` directory. Create two files: `donut.vim` and `chocolate.vim`.\n\nInside `~/.vim/plugin/donut.vim`:\n\n```\necho \"donut!\"\n```\n\nInside `~/.vim/plugin/chocolate.vim`:\n\n```\necho \"chocolate!\"\n```\n\nNow close Vim. The next time you start Vim, you will see both `\"donut!\"` and `\"chocolate!\"` echoed. The plugin runtime path can be used for initializations scripts.\n\n## Filetype Detection\n\nBefore you start, to ensure that these detections work, make sure that your vimrc contains at least the following line:\n\n```\nfiletype plugin indent on\n```\n\nCheck out `:h filetype-overview` for more context. Essentially this turns on Vim's filetype detection.\n\nWhen you open a new file, Vim usually knows what kind of file it is. If you have a file `hello.rb`, running `:set filetype?` returns the correct response `filetype=ruby`.\n\nVim knows how to detect \"common\" file types (Ruby, Python, Javascript, etc). But what if you have a custom file? You need to teach Vim to detect it and assign it with the correct file type.\n\nThere are two methods of detection: using file name and file content.\n\n### File Name Detection\n\nFile name detection detects a file type using the name of that file. When you open the `hello.rb` file, Vim knows it is a Ruby file from the `.rb` extension.\n\nThere are two ways you can do file name detection: using `ftdetect/` runtime directory and using `filetype.vim` runtime file. Let's explore both.\n\n#### `ftdetect/`\n\nLet's create an obscure (yet tasty) file, `hello.chocodonut`. When you open it and you run `:set filetype?`, since it is not a common file name extension Vim doesn't know what to make of it. It returns `filetype=`.\n\nYou need to instruct Vim to set all files ending with `.chocodonut` as a \"chocodonut\" file type. Create a directory named `ftdetect/` in the runtime root (`~/.vim/`). Inside, create a file and name it `chocodonut.vim` (`~/.vim/ftdetect/chocodonut.vim`). Inside this file, add:\n\n```\nautocmd BufNewFile,BufRead *.chocodonut set filetype=chocodonut\n```\n\n`BufNewFile` and `BufRead` are triggered whenever you create a new buffer and open a new buffer. `*.chocodonut` means that this event will only be triggered if the opened buffer has a `.chocodonut` filename extension. Finally, `set filetype=chocodonut` command sets the file type to be a chocodonut type.\n\nRestart Vim. Now open `hello.chocodonut` file and run `:set filetype?`. It returns `filetype=chocodonut`.\n\nScrumptious! You can put as many files as you want inside `ftdetect/`. In the future, you can maybe add `ftdetect/strawberrydonut.vim`, `ftdetect/plaindonut.vim`, etc., if you ever decide to expand your donut file types.\n\nThere are actually two ways to set a file type in Vim. One is what you just used `set filetype=chocodonut`. The other way is to run `setfiletype chocodonut`. The former command `set filetype=chocodonut` will *always* set the file type to chocodonut type, while the latter command `setfiletype chocodonut` will only set the file type if no file type was set yet.\n\n#### Filetype File\n\nThe second file detection method requires you to create a `filetype.vim` in the root directory (`~/.vim/filetype.vim`). Add this inside:\n\n```\nautocmd BufNewFile,BufRead *.plaindonut set filetype=plaindonut\n```\n\nCreate a `hello.plaindonut` file. When you open it and run `:set filetype?`, Vim displays the correct custom file type `filetype=plaindonut`.\n\nHoly pastry, it works! By the way, if you play around with `filetype.vim`, you may notice that this file is being run multiple times when you open `hello.plaindonut`. To prevent this, you can add a guard so the main script is run only once. Update the `filetype.vim`:\n\n```\nif exists(\"did_load_filetypes\")\n  finish\nendif\n\naugroup donutfiletypedetection\n  autocmd! BufRead,BufNewFile *.plaindonut setfiletype plaindonut\naugroup END\n```\n\n`finish` is a Vim command to stop running the rest of the script. The `\"did_load_filetypes\"` expression is *not* a built-in Vim function. It is actually a global variable from inside `$VIMRUNTIME/filetype.vim`. If you're curious, run `:e $VIMRUNTIME/filetype.vim`. You will find these lines inside:\n\n```\nif exists(\"did_load_filetypes\")\n  finish\nendif\n\nlet did_load_filetypes = 1\n```\n\nWhen Vim calls this file, it defines `did_load_filetypes` variable and sets is to 1. 1 is truthy in Vim. You should read the rest of the `filetype.vim` too. See if you can understand what it does when Vim calls it.\n\n### File Type Script\n\nLet's learn how to detect and assign a file type based on the file content.\n\nSuppose you have a collection of files without an agreeable extension. The only thing these files have in common is that they all start with the word \"donutify\" on the first line. You want to assign these files to a `donut` file type. Create new files named `sugardonut`, `glazeddonut`, and `frieddonut` (without extension). Inside each file, add this line:\n\n```\ndonutify\n```\n\nWhen you run the `:set filetype?` from inside `sugardonut`, Vim doesn't know what file type to assign this file with. It returns `filetype=`.\n\nIn the runtime root path, add a `scripts.vim` file (`~/.vim/scripts.vim`). Inside it, add these:\n\n```\nif did_filetype()\n  finish\nendif\n\nif getline(1) =~ '^\\\\<donutify\\\\>'\n  setfiletype donut\nendif\n```\n\nThe function `getline(1)` returns the text on the first line. It checks if the first line starts with the word \"donutify\". The function `did_filetype()` is a Vim built-in function. It will return true when a file type related event is triggered at least once. It is used as a guard to stop re-running file type event.\n\nOpen the `sugardonut` file and run `:set filetype?`, Vim now returns `filetype=donut`. If you open another donut files (`glazeddonut` and `frieddonut`), Vim also identifies their file types as `donut` types.\n\nNote that `scripts.vim` is only run when Vim opens a file with an unknown file type. If Vim opens a file with a known file type, `scripts.vim` won't run.\n\n## File Type Plugin\n\nWhat if you want Vim to run chocodonut-specific scripts when you open a chocodonut file and to not run those scripts when opening plaindonut file?\n\nYou can do this with file type plugin runtime path (`~/.vim/ftplugin/`). Vim looks inside this directory for a file with the same name as the file type you just opened. Create a `chocodonut.vim` (`~/.vim/ftplugin/chocodonut.vim`):\n\n```\necho \"Calling from chocodonut ftplugin\"\n```\n\nCreate another ftplugin file, `plaindonut.vim` (`~/.vim/ftplugin/plaindonut.vim`):\n\n```\necho \"Calling from plaindonut ftplugin\"\n```\n\nNow each time you open a chocodonut file type, Vim runs the scripts from `~/.vim/ftplugin/chocodonut.vim`. Each time you open a plaindonut file type, Vim runs the scripts from `~/.vim/ftplugin/plaindonut.vim`.\n\nOne warning: these files are run each time a buffer file type is set (`set filetype=chocodonut` for example). If you open 3 different chocodonut files, the scripts will be run a *total* of three times.\n\n## Indent Files\n\nVim has an indent runtime path that works similar to ftplugin, where Vim looks for a file named the same as the opened file type. The purpose of these indent runtime paths is to store indent-related codes. If you have the file `~/.vim/indent/chocodonut.vim`, it will be executed only when you open a chocodonut file type. You can store indent-related codes for chocodonut files here.\n\n## Colors\n\nVim has a colors runtime path (`~/.vim/colors/`) to store color schemes. Any file that goes inside the directory will be displayed in the `:color` command-line command.\n\nIf you have a `~/.vim/colors/beautifulprettycolors.vim` file, when you run `:color` and press Tab, you will see `beautifulprettycolors` as one of the color options. If you prefer to add your own color scheme, this is the place to go.\n\nIf you want to check out the color schemes other people made, a good place to visit is [vimcolors](https://vimcolors.com/).\n\n## Syntax Highlighting\n\nVim has a syntax runtime path (`~/.vim/syntax/`) to define syntax highlighting.\n\nSuppose you have a `hello.chocodonut` file, inside it you have the following expressions:\n\n```\n(donut \"tasty\")\n(donut \"savory\")\n```\n\nAlthough Vim now knows the correct file type, all texts have the same color. Let's add a syntax highlighting rule to highlight the \"donut\" keyword. Create a new chocodonut syntax file, `~/.vim/syntax/chocodonut.vim`. Inside it add:\n\n```\nsyntax keyword donutKeyword donut\n\nhighlight link donutKeyword Keyword\n```\n\nNow reopen `hello.chocodonut` file. The `donut` keywords are now highlighted.\n\nThis chapter won't go over syntax highlighting in depth. It is a vast topic. If you are curious, check out `:h syntax.txt`.\n\nThe [vim-polyglot](https://github.com/sheerun/vim-polyglot) plugin is a great plugin that provides highlights for many popular programming languages.\n\n## Documentation\n\nIf you create a plugin, you will have to create your own documentation. You use the doc runtime path for that.\n\nLet's create a basic documentation for chocodonut and plaindonut keywords. Create a `donut.txt` (`~/.vim/doc/donut.txt`). Inside, add these texts:\n\n```\n*chocodonut* Delicious chocolate donut\n\n*plaindonut* No choco goodness but still delicious nonetheless\n```\n\nIf you try to search for `chocodonut` and `plaindonut` (`:h chocodonut` and `:h plaindonut`), you won't find anything.\n\nFirst, you need to run `:helptags` to generate new help entries. Run `:helptags ~/.vim/doc/`\n\nNow if you run `:h chocodonut` and `:h plaindonut`, you will find these new help entries. Notice that the file is now read-only and has a \"help\" file type.\n\n## Lazy Loading Scripts\n\nAll of the runtime paths that you learned in this chapter were run automatically. If you want to manually load a script, use the autoload runtime path.\n\nCreate an autoload directory (`~/.vim/autoload/`). Inside that directory, create a new file and name it `tasty.vim` (`~/.vim/autoload/tasty.vim`). Inside it:\n\n```\necho \"tasty.vim global\"\n\nfunction tasty#donut()\n  echo \"tasty#donut\"\nendfunction\n```\n\nNote that the function name is `tasty#donut`, not `donut()`. The pound sign (`#`) is required when using the autoload feature. The function naming convention for the autoload feature is:\n\n```\nfunction fileName#functionName()\n  ...\nendfunction\n```\n\nIn this case, the file name is `tasty.vim` and the function name is (technically) `donut`.\n\nTo invoke a function, you need the `call` command. Let's call that function with `:call tasty#donut()`.\n\nThe first time you call the function, you should see *both* echo messages (\"tasty.vim global\" and \"tasty#donut\"). The subsequent calls to` tasty#donut` function will only display \"tasty#donut\" echo.\n\nWhen you open a file in Vim, unlike the previous runtime paths, autoload scripts aren't loaded automatically. Only when you explicitly call `tasty#donut()`, Vim looks for the `tasty.vim` file and loads everything inside it, including the `tasty#donut()` function. Autoload is the perfect mechanism for functions that use extensive resources but you don't use often.\n\nYou can add as many nested directories with autoload as you want. If you have the runtime path `~/.vim/autoload/one/two/three/tasty.vim`, you can call the function with `:call one#two#three#tasty#donut()`.\n\n## After Scripts\n\nVim has an after runtime path (`~/.vim/after/`) that mirrors the structure of `~/.vim/`. Anything in this path is executed last, so developers usually use these paths for script overrides.\n\nFor example, if you want to overwrite the scripts from `plugin/chocolate.vim`, you can create `~/.vim/after/plugin/chocolate.vim` to put the override scripts. Vim will run the `~/.vim/after/plugin/chocolate.vim` *after* `~/.vim/plugin/chocolate.vim`.\n\n## $VIMRUNTIME\n\nVim has an environment variable `$VIMRUNTIME` for default scripts and support files. You can check it out by running `:e $VIMRUNTIME`.\n\nThe structure should look familiar. It contains many runtime paths you learned in this chapter.\n\nRecall in Chapter 21, you learned that when you open Vim, it looks for a vimrc files in seven different locations. I said that the last location Vim checks is `$VIMRUNTIME/defaults.vim`. If Vim fails to find any user vimrc files, Vim uses a `defaults.vim` as vimrc.\n\nHave you ever tried running Vim without a syntax plugin like vim-polyglot and yet your file is still syntactically highlighted? That is because when Vim fails to find a syntax file from the runtime path, Vim looks for a syntax file from `$VIMRUNTIME` syntax directory.\n\nTo learn more, check out `:h $VIMRUNTIME`.\n\n## Runtimepath Option\n\nTo check your runtimepath, run `:set runtimepath?`\n\nIf you use Vim-Plug or popular external plugin managers, it should display a list of directories. For example, mine shows:\n\n```\nruntimepath=~/.vim,~/.vim/plugged/vim-signify,~/.vim/plugged/base16-vim,~/.vim/plugged/fzf.vim,~/.vim/plugged/fzf,~/.vim/plugged/vim-gutentags,~/.vim/plugged/tcomment_vim,~/.vim/plugged/emmet-vim,~/.vim/plugged/vim-fugitive,~/.vim/plugged/vim-sensible,~/.vim/plugged/lightline.vim, ...\n```\n\nOne of the things plugin managers does is adding each plugin into the runtime path. Each runtime path can have its own directory structure similar to `~/.vim/`.\n\nIf you have a directory `~/box/of/donuts/` and you want to add that directory to your runtime path, you can add this to your vimrc:\n\n```\nset rtp+=$HOME/box/of/donuts/\n```\n\nIf inside `~/box/of/donuts/`, you have a plugin directory (`~/box/of/donuts/plugin/hello.vim`) and a ftplugin (`~/box/of/donuts/ftplugin/chocodonut.vim`), Vim will run all scripts from `plugin/hello.vim` when you open Vim. Vim will also run `ftplugin/chocodonut.vim` when you open a chocodonut file.\n\nTry this yourself: create an arbitrary path and add it to your runtimepath. Add some of the runtime paths you learned from this chapter. Make sure they work as expected.\n\n## Learn Runtime the Smart Way\n\nTake your time reading it and play around with these runtime paths. To see how runtime paths are being used in the wild, go to the repository of one of your favorite Vim plugins and study its directory structure. You should be able to understand most of them now. Try to follow along and discern the big picture. Now that you understand Vim directory structure, you're ready to learn Vimscript.\n\n## Link\n- Prev [Ch23. Vim Packages](./ch23_vim_packages.md)\n- Next [Ch25. Vimscript Basic Data Types](./ch25_vimscript_basic_data_types.md)\n"
  },
  {
    "path": "ch25_vimscript_basic_data_types.md",
    "content": "# Ch25. Vimscript Basic Data Types\n\nIn the next few chapters, you will learn about Vimscript, Vim's built-in programming language.\n\nWhen learning a new language, there are three basic elements to look for:\n- Primitives\n- Means of Combination\n- Means of Abstraction\n\nIn this chapter, you will learn Vim's primitive data types.\n\n## Data Types\n\nVim has 10 different data types:\n- Number\n- Float\n- String\n- List\n- Dictionary\n- Special\n- Funcref\n- Job\n- Channel\n- Blob\n\nI will cover the first six data types here. In Ch. 27, you will learn about Funcref. For more about Vim data types, check out `:h variables`.\n\n## Following Along With Ex Mode\n\nVim technically does not have a built-in REPL, but it has a mode, Ex mode, that can be used like one. You can go to the Ex mode with `Q` or `gQ`. The Ex mode is like an extended command-line mode (it's like typing command-line mode commands non-stop). To quit the Ex mode, type `:visual`.\n\nYou can use either `:echo` or `:echom` on this chapter and the subsequent Vimscript chapters to code along. They are like `console.log` in JS or `print` in Python. The `:echo` command prints the evaluated expression you give. The `:echom` command does the same, but in addition, it stores the result in the message history.\n\n```viml\n:echom \"hello echo message\"\n```\n\nYou can view the message history with:\n\n```\n:messages\n```\n\nTo clear your message history, run:\n\n```\n:messages clear\n```\n\n## Number\n\nVim has 4 different number types: decimal, hexadecimal, binary, and octal. By the way, when I say number data type, often this means an integer data type. In this guide, I will use the terms number and integer interchangeably.\n\n### Decimal\n\nYou should be familiar with the decimal system. Vim accepts positive and negative decimals. 1, -1, 10, etc. In Vimscript programming, you will probably be using the decimal type most of the time.\n\n### Hexadecimal\n\nHexadecimals start with `0x` or `0X`. Mnemonic: He**x**adecimal.\n\n### Binary\n\nBinaries start with `0b` or `0B`. Mnemonic: **B**inary.\n\n### Octal\n\nOctals start with `0`, `0o`, and `0O`. Mnemonic: **O**ctal.\n\n### Printing Numbers\n\nIf you `echo` either a hexadecimal, a binary, or an octal number, Vim automatically converts them to decimals.\n\n```viml\n:echo 42\n\" returns 42\n\n:echo 052\n\" returns 42\n\n:echo 0b101010\n\" returns 42\n\n:echo 0x2A\n\" returns 42\n```\n\n### Truthy and Falsy\n\nIn Vim, a 0 value is falsy and all non-0 values are truthy.\n\nThe following will not echo anything.\n\n```viml\n:if 0\n:  echo \"Nope\"\n:endif\n```\n\nHowever, this will:\n\n```viml\n:if 1\n:  echo \"Yes\"\n:endif\n```\n\nAny value other than 0 is truthy, including negative numbers. 100 is truthy. -1 is truthy.\n\n### Number Arithmetic\n\nNumbers can be used to run arithmetic expressions:\n\n```viml\n:echo 3 + 1\n\" returns 4\n\n: echo 5 - 3\n\" returns 2\n\n:echo 2 * 2\n\" returns 4\n\n:echo 4 / 2\n\" returns 2\n```\n\nWhen dividing a number with a remainder, Vim drops the remainder.\n\n```viml\n:echo 5 / 2\n\" returns 2 instead of 2.5\n```\n\nTo get a more accurate result, you need to use a float number.\n\n## Float\n\nFloats are numbers with trailing decimals. There are two ways to represent floating numbers: dot point notation (like 31.4) and exponent (3.14e01). Similar to numbers, you can use positive and negative signs:\n\n```viml\n:echo +123.4\n\" returns 123.4\n\n:echo -1.234e2\n\" returns -123.4\n\n:echo 0.25\n\" returns 0.25\n\n:echo 2.5e-1\n\" returns 0.25\n```\n\nYou need to give a float a dot and trailing digits. `25e-2` (no dot) and `1234.` (has a dot, but no trailing digits) are both invalid float numbers.\n\n### Float Arithmetic\n\nWhen doing an arithmetic expression between a number and a float, Vim coerces the result to a float.\n\n```viml\n:echo 5 / 2.0\n\" returns 2.5\n```\n\nFloat and float arithmetic gives you another float.\n\n```\n:echo 1.0 + 1.0\n\" returns 2.0\n```\n\n## String\n\nStrings are characters surrounded by either double-quotes (`\"\"`) or single-quotes (`''`). \"Hello\", \"123\", and '123.4' are examples of strings.\n\n### String Concatenation\n\nTo concatenate a string in Vim, use the `.` operator.\n\n```viml\n:echo \"Hello\" . \" world\"\n\" returns \"Hello world\"\n```\n\n### String Arithmetic\n\nWhen you run arithmetic operators (`+ - * /`) with a number and a string, Vim coerces the string into a number.\n\n```viml\n:echo \"12 donuts\" + 3\n\" returns 15\n```\n\nWhen Vim sees \"12 donuts\", it extracts the 12 from the string and converts it into the number 12. Then it performs addition, returning 15. For this string-to-number coercion to work, the number character needs to be the *first character* in the string.\n\nThe following won't work because 12 is not the first character in the string:\n\n```viml\n:echo \"donuts 12\" + 3\n\" returns 3\n```\n\nThis also won't work because an empty space is the first character of the string:\n\n```viml\n:echo \" 12 donuts\" + 3\n\" returns 3\n```\n\nThis coercion works even with two strings:\n\n```\n:echo \"12 donuts\" + \"6 pastries\"\n\" returns 18\n```\n\nThis works with any arithmetic operator, not only `+`:\n\n```viml\n:echo \"12 donuts\" * \"5 boxes\"\n\" returns 60\n\n:echo \"12 donuts\" - 5\n\" returns 7\n\n:echo \"12 donuts\" / \"3 people\"\n\" returns 4\n```\n\nA neat trick to force a string-to-number conversion is to just add 0 or multiply by 1:\n\n```viml\n:echo \"12\" + 0\n\" returns 12\n\n:echo \"12\" * 1\n\" returns 12\n```\n\nWhen arithmetic is done against a float in a string, Vim treats it like an integer, not a float:\n\n```\n:echo \"12.0 donuts\" + 12\n\" returns 24, not 24.0\n```\n\n### Number and String Concatenation\n\nYou can coerce a number into a string with a dot operator (`.`):\n\n```viml\n:echo 12 . \"donuts\"\n\" returns \"12donuts\"\n```\n\nThe coercion only works with number data type, not float. This won't work:\n\n```\n:echo 12.0 . \"donuts\"\n\" does not return \"12.0donuts\" but throws an error\n```\n\n### String Conditionals\n\nRecall that 0 is falsy and all non-0 numbers are truthy. This is also true when using string as conditionals.\n\nIn the following if statement, Vim coerces \"12donuts\" into 12, which is truthy:\n\n```viml\n:if \"12donuts\"\n:  echo \"Yum\"\n:endif\n\" returns \"Yum\"\n```\n\nOn the other hand, this is falsy:\n\n```viml\n:if \"donuts12\"\n:  echo \"Nope\"\n:endif\n\" returns nothing\n```\n\nVim coerces \"donuts12\" into 0, because the first character is not a number.\n\n### Double vs Single Quotes\n\nDouble quotes behave differently than single quotes. Single quotes display characters literally while double quotes accept special characters.\n\nWhat are special characters? Check out the newline and double-quotes display:\n\n```viml\n:echo \"hello\\nworld\"\n\" returns\n\" hello\n\" world\n\n:echo \"hello \\\"world\\\"\"\n\" returns \"hello \"world\"\"\n```\n\nCompare that with single-quotes:\n\n```\n:echo 'hello\\nworld'\n\" returns 'hello\\nworld'\n\n:echo 'hello \\\"world\\\"'\n\" returns 'hello \\\"world\\\"'\n```\n\nSpecial characters are special string characters that when escaped, behave differently. `\\n` acts like a newline. `\\\"` behaves like a literal `\"`. For a list of other special characters, check out `:h expr-quote`.\n\n### String Procedures\n\nLet's look at some built-in string procedures.\n\nYou can get the length of a string with `strlen()`.\n\n```\n:echo strlen(\"choco\")\n\" returns 5\n```\n\nYou can convert string to a number with `str2nr()`:\n\n```\n:echo str2nr(\"12donuts\")\n\" returns 12\n\n:echo str2nr(\"donuts12\")\n\" returns 0\n```\n\nSimilar to the string-to-number coercion earlier, if the number is not the first character, Vim won't catch it.\n\nThe good news is that Vim has a method that transforms a string to a float, `str2float()`:\n\n```\n:echo str2float(\"12.5donuts\")\n\" returns 12.5\n```\n\nYou can substitute a pattern in a string with the `substitute()` method:\n\n```\n:echo substitute(\"sweet\", \"e\", \"o\", \"g\")\n\" returns \"swoot\"\n```\n\nThe last parameter, \"g\", is the global flag. With it, Vim will substitute all matching occurrences. Without it, Vim will only substitute the first match.\n\n```\n:echo substitute(\"sweet\", \"e\", \"o\", \"\")\n\" returns \"swoet\"\n```\n\nThe substitute command can be combined with `getline()`. Recall that the function `getline()` gets the text on the given line number. Suppose you have the text \"chocolate donut\" on line 5. You can use the procedure:\n\n```\n:echo substitute(getline(5), \"chocolate\", \"glazed\", \"g\")\n\" returns glazed donut\n```\n\nThere are many other string procedures. Check out `:h string-functions`.\n\n## List\n\nA Vimscript list is like an Array in Javascript or List in Python. It is an *ordered* sequence of items. You can mix-and-match the content with different data types:\n\n```\n[1,2,3]\n['a', 'b', 'c']\n[1,'a', 3.14]\n[1,2,[3,4]]\n```\n\n### Sublists\n\nVim list is zero-indexed. You can access a particular item in a list with `[n]`, where n is the index.\n\n```\n:echo [\"a\", \"sweet\", \"dessert\"][0]\n\" returns \"a\"\n\n:echo [\"a\", \"sweet\", \"dessert\"][2]\n\" returns \"dessert\"\n```\n\nIf you go over the maximum index number, Vim will throw an error saying that the index is out of range:\n\n```\n:echo [\"a\", \"sweet\", \"dessert\"][999]\n\" returns an error\n```\n\nWhen you go below zero, Vim will start the index from the last element. Going past the minimum index number will also throw you an error:\n\n```\n:echo [\"a\", \"sweet\", \"dessert\"][-1]\n\" returns \"dessert\"\n\n:echo [\"a\", \"sweet\", \"dessert\"][-3]\n\" returns \"a\"\n\n:echo [\"a\", \"sweet\", \"dessert\"][-999]\n\" returns an error\n```\n\nYou can \"slice\" several elements from a list with `[n:m]`, where `n` is the starting index and `m` is the ending index.\n\n```\n:echo [\"chocolate\", \"glazed\", \"plain\", \"strawberry\", \"lemon\", \"sugar\", \"cream\"][2:4]\n\" returns [\"plain\", \"strawberry\", \"lemon\"]\n```\n\nIf you don't pass `m` (`[n:]`), Vim will return the rest of the elements starting from the nth element. If you don't pass `n` (`[:m]`), Vim will return the first element up to the mth element.\n\n```\n:echo [\"chocolate\", \"glazed\", \"plain\", \"strawberry\", \"lemon\", \"sugar\", \"cream\"][2:]\n\" returns ['plain', 'strawberry', 'lemon', 'sugar', 'cream']\n\n:echo [\"chocolate\", \"glazed\", \"plain\", \"strawberry\", \"lemon\", \"sugar\", \"cream\"][:4]\n\" returns ['chocolate', 'glazed', 'plain', 'strawberry', 'lemon']\n```\n\nYou can pass an index that exceeds the maximum items when slicing an array.\n\n```viml\n:echo [\"chocolate\", \"glazed\", \"plain\", \"strawberry\", \"lemon\", \"sugar\", \"cream\"][2:999]\n\" returns ['plain', 'strawberry', 'lemon', 'sugar', 'cream']\n```\n\n### Slicing String\n\nYou can slice and target strings just like lists:\n\n```viml\n:echo \"choco\"[0]\n\" returns \"c\"\n\n:echo \"choco\"[1:3]\n\" returns \"hoc\"\n\n:echo \"choco\"[:3]\n\" returns choc\n\n:echo \"choco\"[1:]\n\" returns hoco\n```\n\n### List Arithmetic\n\nYou can use `+` to concatenate and mutate a list:\n\n```viml\n:let sweetList = [\"chocolate\", \"strawberry\"]\n:let sweetList += [\"sugar\"]\n:echo sweetList\n\" returns [\"chocolate\", \"strawberry\", \"sugar\"]\n```\n\n### List Functions\n\nLet's explore Vim's built-in list functions.\n\nTo get the length of a list, use `len()`:\n\n```\n:echo len([\"chocolate\", \"strawberry\"])\n\" returns 2\n```\n\nTo prepend an element to a list, you can use `insert()`:\n\n```\n:let sweetList = [\"chocolate\", \"strawberry\"]\n:call insert(sweetList, \"glazed\")\n\n:echo sweetList\n\" returns [\"glazed\", \"chocolate\", \"strawberry\"]\n```\n\nYou can also pass `insert()` the index where you want to prepend the element to. If you want to prepend an item before the second element (index 1):\n\n```\n:let sweeterList = [\"glazed\", \"chocolate\", \"strawberry\"]\n:call insert(sweeterList, \"cream\", 1)\n\n:echo sweeterList\n\" returns ['glazed', 'cream', 'chocolate', 'strawberry']\n```\n\nTo remove a list item, use `remove()`. It accepts a list and the element index you want to remove.\n\n```\n:let sweeterList = [\"glazed\", \"chocolate\", \"strawberry\"]\n:call remove(sweeterList, 1)\n\n:echo sweeterList\n\" returns ['glazed', 'strawberry']\n```\n\nYou can use `map()` and `filter()` on a list. To filter out element containing the phrase \"choco\":\n\n```\n:let sweeterList = [\"glazed\", \"chocolate\", \"strawberry\"]\n:call filter(sweeterList, 'v:val !~ \"choco\"')\n:echo sweeterList\n\" returns [\"glazed\", \"strawberry\"]\n\n:let sweetestList = [\"chocolate\", \"glazed\", \"sugar\"]\n:call map(sweetestList, 'v:val . \" donut\"')\n:echo sweetestList\n\" returns ['chocolate donut', 'glazed donut', 'sugar donut']\n```\n\nThe `v:val` variable is a Vim special variable. It is available when iterating a list or a dictionary using `map()` or `filter()`. It represents each iterated item.\n\nFor more, check out `:h list-functions`.\n\n### List Unpacking\n\nYou can unpack a list and assign variables to the list items:\n\n```\n:let favoriteFlavor = [\"chocolate\", \"glazed\", \"plain\"]\n:let [flavor1, flavor2, flavor3] = favoriteFlavor\n\n:echo flavor1\n\" returns \"chocolate\"\n\n:echo flavor2\n\" returns \"glazed\"\n```\n\nTo assign the rest of list items, you can use `;` followed with a variable name:\n\n```\n:let favoriteFruits = [\"apple\", \"banana\", \"lemon\", \"blueberry\", \"raspberry\"]\n:let [fruit1, fruit2; restFruits] = favoriteFruits\n\n:echo fruit1\n\" returns \"apple\"\n\n:echo restFruits\n\" returns ['lemon', 'blueberry', 'raspberry']\n```\n\n### Modifying List\n\nYou can modify a list item directly:\n\n```\n:let favoriteFlavor = [\"chocolate\", \"glazed\", \"plain\"]\n:let favoriteFlavor[0] = \"sugar\"\n:echo favoriteFlavor\n\" returns ['sugar', 'glazed', 'plain']\n```\n\nYou can mutate multiple list items directly:\n\n```\n:let favoriteFlavor = [\"chocolate\", \"glazed\", \"plain\"]\n:let favoriteFlavor[2:] = [\"strawberry\", \"chocolate\"]\n:echo favoriteFlavor\n\" returns ['chocolate', 'glazed', 'strawberry', 'chocolate']\n```\n\n## Dictionary\n\nA Vimscript dictionary is an associative, unordered list. A non-empty dictionary consists of at least a key-value pair.\n\n```\n{\"breakfast\": \"waffles\", \"lunch\": \"pancakes\"}\n{\"meal\": [\"breakfast\", \"second breakfast\", \"third breakfast\"]}\n{\"dinner\": 1, \"dessert\": 2}\n```\n\nA Vim dictionary data object uses string for key. If you try to use a number, Vim will coerce it into a string.\n\n```\n:let breakfastNo = {1: \"7am\", 2: \"9am\", \"11ses\": \"11am\"}\n\n:echo breakfastNo\n\" returns {'1': '7am', '2': '9am', '11ses': '11am'}\n```\n\nIf you are too lazy to put quotes around each key, you can use the `#{}` notation:\n\n```\n:let mealPlans = #{breakfast: \"waffles\", lunch: \"pancakes\", dinner: \"donuts\"}\n\n:echo mealPlans\n\" returns {'lunch': 'pancakes', 'breakfast': 'waffles', 'dinner': 'donuts'}\n```\n\nThe only requirement for using the `#{}` syntax is that each key must be either:\n\n- ASCII character.\n- Digit.\n- An underscore (`_`).\n- A hyphen (`-`).\n\nJust like list, you can use any data type as values.\n\n```\n:let mealPlan = {\"breakfast\": [\"pancake\", \"waffle\", \"hash brown\"], \"lunch\": WhatsForLunch(), \"dinner\": {\"appetizer\": \"gruel\", \"entree\": \"more gruel\"}}\n```\n\n### Accessing Dictionary\n\nTo access a value from a dictionary, you can call the key with either the square brackets (`['key']`) or the dot notation (`.key`).\n\n```\n:let meal = {\"breakfast\": \"gruel omelettes\", \"lunch\": \"gruel sandwiches\", \"dinner\": \"more gruel\"}\n\n:let breakfast = meal['breakfast']\n:let lunch = meal.lunch\n\n:echo breakfast\n\" returns \"gruel omelettes\"\n\n:echo lunch\n\" returns \"gruel sandwiches\"\n```\n\n### Modifying Dictionary\n\nYou can modify or even add a dictionary content:\n\n```\n:let meal = {\"breakfast\": \"gruel omelettes\", \"lunch\": \"gruel sandwiches\"}\n\n:let meal.breakfast = \"breakfast tacos\"\n:let meal[\"lunch\"] = \"tacos al pastor\"\n:let meal[\"dinner\"] = \"quesadillas\"\n\n:echo meal\n\" returns {'lunch': 'tacos al pastor', 'breakfast': 'breakfast tacos', 'dinner': 'quesadillas'}\n```\n\n### Dictionary Functions\n\nLet's explore some of Vim's built-in functions to handle dictionaries.\n\nTo check the length of a dictionary, use `len()`.\n\n```\n:let mealPlans = #{breakfast: \"waffles\", lunch: \"pancakes\", dinner: \"donuts\"}\n\n:echo len(mealPlans)\n\" returns 3\n```\n\nTo see if a dictionary contains a specific key, use `has_key()`.\n\n```\n:let mealPlans = #{breakfast: \"waffles\", lunch: \"pancakes\", dinner: \"donuts\"}\n\n:echo has_key(mealPlans, \"breakfast\")\n\" returns 1\n\n:echo has_key(mealPlans, \"dessert\")\n\" returns 0\n```\n\nTo see if a dictionary has any item, use `empty()`. The `empty()` procedure works with all data types: list, dictionary, string, number, float, etc.\n\n```\n:let mealPlans = #{breakfast: \"waffles\", lunch: \"pancakes\", dinner: \"donuts\"}\n:let noMealPlan = {}\n\n:echo empty(noMealPlan)\n\" returns 1\n\n:echo empty(mealPlans)\n\" returns 0\n```\n\nTo remove an entry from a dictionary, use `remove()`.\n\n```\n:let mealPlans = #{breakfast: \"waffles\", lunch: \"pancakes\", dinner: \"donuts\"}\n\n:echo \"removing breakfast: \" . remove(mealPlans, \"breakfast\")\n\" returns \"removing breakfast: 'waffles'\"\"\n\n:echo mealPlans\n\" returns {'lunch': 'pancakes', 'dinner': 'donuts'}\n```\n\nTo convert a dictionary into a list of lists, use `items()`:\n\n```\n:let mealPlans = #{breakfast: \"waffles\", lunch: \"pancakes\", dinner: \"donuts\"}\n\n:echo items(mealPlans)\n\" returns [['lunch', 'pancakes'], ['breakfast', 'waffles'], ['dinner', 'donuts']]\n```\n\n`filter()` and `map()` are also available.\n\n```\n:let breakfastNo = {1: \"7am\", 2: \"9am\", \"11ses\": \"11am\"}\n:call filter(breakfastNo, 'v:key > 1')\n\n:echo breakfastNo\n\" returns {'2': '9am', '11ses': '11am'}\n```\n\nSince a dictionary contains key-value pairs, Vim provides `v:key` special variable that works similar to `v:val`. When iterating through a dictionary, `v:key` will hold the value of the current iterated key. \n\nIf you have a `mealPlans` dictionary, you can map it using `v:key`.\n\n```\n:let mealPlans = #{breakfast: \"waffles\", lunch: \"pancakes\", dinner: \"donuts\"}\n:call map(mealPlans, 'v:key . \" and milk\"')\n\n:echo mealPlans\n\" returns {'lunch': 'lunch and milk', 'breakfast': 'breakfast and milk', 'dinner': 'dinner and milk'}\n```\n\nSimilarly, you can map it using `v:val`:\n\n```\n:let mealPlans = #{breakfast: \"waffles\", lunch: \"pancakes\", dinner: \"donuts\"}\n:call map(mealPlans, 'v:val . \" and milk\"')\n\n:echo mealPlans\n\" returns {'lunch': 'pancakes and milk', 'breakfast': 'waffles and milk', 'dinner': 'donuts and milk'}\n```\n\nTo see more dictionary functions, check out `:h dict-functions`.\n\n## Special Primitives\n\nVim has special primitives:\n\n- `v:false`\n- `v:true`\n- `v:none`\n- `v:null`\n\nBy the way, `v:` is Vim's built-in variable. They will be covered more in a later chapter.\n\nIn my experience, you won't use these special primitives often. If you need a truthy / falsy value, you can just use 0 (falsy) and non-0 (truthy). If you need an empty string, just use `\"\"`. But it is still good to know, so let's quickly go over them.\n\n### True\n\nThis is equivalent to `true`. It is equivalent to a number with value of non-0 . When decoding json with `json_encode()`, it is interpreted as \"true\".\n\n```\n:echo json_encode({\"test\": v:true})\n\" returns {\"test\": true}\n```\n\n### False\n\nThis is equivalent to `false`. It is equivalent to a number with value of 0. When decoding json with `json_encode()`, it is interpreted as \"false\".\n\n```\n:echo json_encode({\"test\": v:false})\n\" returns {\"test\": false}\n```\n\n### None\n\nIt is equivalent to an empty string. When decoding json with `json_encode()`, it is interpreted as an empty item (`null`).\n\n```\n:echo json_encode({\"test\": v:none})\n\" returns {\"test\": null}\n```\n\n### Null\n\nSimilar to `v:none`.\n\n```\n:echo json_encode({\"test\": v:null})\n\" returns {\"test\": null}\n```\n\n## Learn Data Types the Smart Way\n\nIn this chapter, you learned about Vimscript's basic data types: number, float, string, list, dictionary, and special. Learning these is the first step to start Vimscript programming.\n\nIn the next chapter, you will learn how to combine them for writing expressions like equalities, conditionals, and loops.\n\n## Link\n- Prev [Ch24. Vim Runtime](./ch24_vim_runtime.md)\n- Next [Ch26. Vimscript Conditionals and Loops](./ch26_vimscript_conditionals_and_loops.md)\n"
  },
  {
    "path": "ch26_vimscript_conditionals_and_loops.md",
    "content": "# Ch26. Vimscript Conditionals and Loops\n\nAfter learning what the basic data types are, the next step is to learn how to combine them together to start writing a basic program. A basic program consists of conditionals and loops.\n\nIn this chapter, you will learn how to use Vimscript data types to write conditionals and loops.\n\n## Relational Operators\n\nVimscript relational operators are similar to many programming languages:\n\n```\na == b\t\tequal to\na != b\t\tnot equal to\na >  b\t\tgreater than\na >= b\t\tgreater than or equal to\na <  b\t\tless than\na <= b\t\tless than or equal to\n```\n\nFor example:\n\n```\n:echo 5 == 5\n:echo 5 != 5\n:echo 10 > 5\n:echo 10 >= 5\n:echo 10 < 5\n:echo 5 <= 5\n```\n\nRecall that strings are coerced into numbers in an arithmetic expression. Here Vim also coerces strings into numbers in an equality expression. \"5foo\" is coerced into 5 (truthy):\n\n```\n:echo 5 == \"5foo\"\n\" returns true\n```\n\nAlso recall that if you start a string with a non-numerical character like \"foo5\", the string is converted into number 0 (falsy).\n\n```\necho 5 == \"foo5\"\n\" returns false\n```\n\n### String Logic Operators\n\nVim has more relational operators for comparing strings:\n\n```\na =~ b\na !~ b\n```\n\nFor examples:\n\n```\nlet str = \"hearty breakfast\"\n\necho str =~ \"hearty\"\n\" returns true\n\necho str =~ \"dinner\"\n\" returns false\n\necho str !~ \"dinner\"\n\" returns true\n```\n\nThe `=~` operator performs a regex match against the given string. In the example above, `str =~ \"hearty\"` returns true because `str` *contains* the \"hearty\" pattern. You can always use `==` and `!=`, but using them will compare the expression against the entire string. `=~` and `!~` are more flexible choices.\n\n```\necho str == \"hearty\"\n\" returns false\n\necho str == \"hearty breakfast\"\n\" returns true\n```\n\nLet's try this one. Note the uppercase \"H\":\n\n```\necho str =~ \"Hearty\"\n\" true\n```\n\nIt returns true even though \"Hearty\" is capitalized. Interesting... It turns out that my Vim setting is set to ignore case (`set ignorecase`), so when Vim checks for equality, it uses my Vim setting and ignores the case. If I were to turn off ignore case (`set noignorecase`), the comparison now returns false.\n\n```\nset noignorecase\necho str =~ \"Hearty\"\n\" returns false because case matters\n\nset ignorecase\necho str =~ \"Hearty\"\n\" returns true because case doesn't matter\n```\n\nIf you are writing a plugin for others, this is a tricky situation. Does the user use `ignorecase` or `noignorecase`? You definitely do *not* want to force your users to change their ignore case option. So what do you do?\n\nLuckily, Vim has an operator that can *always* ignore or match case. To always match case, add a `#` at the end.\n\n```\nset ignorecase\necho str =~# \"hearty\"\n\" returns true\n\necho str =~# \"HearTY\"\n\" returns false\n\nset noignorecase\necho str =~# \"hearty\"\n\" true\n\necho str =~# \"HearTY\"\n\" false\n\necho str !~# \"HearTY\"\n\" true\n```\n\nTo always ignore case when comparing, append it with `?`:\n\n```\nset ignorecase\necho str =~? \"hearty\"\n\" true\n\necho str =~? \"HearTY\"\n\" true\n\nset noignorecase\necho str =~? \"hearty\"\n\" true\n\necho str =~? \"HearTY\"\n\" true\n\necho str !~? \"HearTY\"\n\" false\n```\n\nI prefer to use `#` to always match the case and be on the safe side.\n\n## If\n\nNow that you have seen Vim's equality expressions, let's touch a fundamental conditional operator, the `if` statement.\n\nAt minimum, the syntax is:\n\n```\nif {clause}\n  {some expression}\nendif\n```\n\nYou can extend the case analysis with `elseif` and `else`.\n\n```\nif {predicate1}\n  {expression1}\nelseif {predicate2}\n  {expression2}\nelseif {predicate3}\n  {expression3}\nelse\n  {expression4}\nendif\n```\n\nFor example, the plugin [vim-signify](https://github.com/mhinz/vim-signify) uses a different installation method depending on your Vim settings. Below is the installation instruction from their `readme`, using the `if` statement:\n\n```\nif has('nvim') || has('patch-8.0.902')\n  Plug 'mhinz/vim-signify'\nelse\n  Plug 'mhinz/vim-signify', { 'branch': 'legacy' }\nendif\n```\n\n## Ternary Expression\n\nVim has a ternary expression for a one-liner case analysis:\n\n```\n{predicate} ? expressiontrue : expressionfalse\n```\n\nFor example:\n\n```\necho 1 ? \"I am true\" : \"I am false\"\n```\n\nSince 1 is truthy, Vim echoes \"I am true\". Suppose you want to conditionally set the `background` to dark if you are using Vim past a certain hour. Add this to vimrc:\n\n```\nlet &background = strftime(\"%H\") < 18 ? \"light\" : \"dark\"\n```\n\n`&background` is the `'background'` option in Vim. `strftime(\"%H\")` returns the current time in hours. If it is not yet 6 PM, use a light background. Otherwise, use a dark background.\n\n## or\n\nThe logical \"or\" (`||`) works like many programming languages.\n\n```\n{Falsy expression}  || {Falsy expression}   false\n{Falsy expression}  || {Truthy expression}  true\n{Truthy expression} || {Falsy expression}   true\n{Truthy expression} || {Truthy expression}  true\n```\n\nVim evaluates the expression and return either 1 (truthy) or 0 (falsy).\n\n```\necho 5 || 0\n\" returns 1\n\necho 5 || 5\n\" returns 1\n\necho 0 || 0\n\" returns 0\n\necho \"foo5\" || \"foo5\"\n\" returns 0\n\necho \"5foo\" || \"foo5\"\n\" returns 1\n```\n\nIf the current expression evaluates to truthy, the subsequent expression won't be evaluated.\n\n```\nlet one_dozen = 12\n\necho one_dozen || two_dozen\n\" returns 1\n\necho two_dozen || one_dozen\n\" returns error\n```\n\nNote that `two_dozen` is never defined. The expression `one_dozen || two_dozen` doesn't throw any error because `one_dozen` is evaluated first found to be truthy, so Vim doesn't evaluate `two_dozen`.\n\n## and\n\nThe logical \"and\" (`&&`) is the complement of the logical or.\n\n```\n{Falsy Expression}  && {Falsy Expression}   false\n{Falsy expression}  && {Truthy expression}  false\n{Truthy Expression} && {Falsy Expression}   false\n{Truthy expression} && {Truthy expression}  true\n```\n\nFor example:\n\n```\necho 0 && 0\n\" returns 0\n\necho 0 && 10\n\" returns 0\n```\n\n`&&` evaluates an expression until it sees the first falsy expression. For example, if you have `true && true`, it will evaluate both and return `true`. If you have `true && false && true`, it will evaluate the first `true` and stop at the first `false`. It will not evaluate the third `true`.\n\n```\nlet one_dozen = 12\necho one_dozen && 10\n\" returns 1\n\necho one_dozen && v:false\n\" returns 0\n\necho one_dozen && two_dozen\n\" returns error\n\necho exists(\"one_dozen\") && one_dozen == 12\n\" returns 1\n```\n\n## for\n\nThe `for` loop is commonly used with the list data type.\n\n```\nlet breakfasts = [\"pancakes\", \"waffles\", \"eggs\"]\n\nfor breakfast in breakfasts\n  echo breakfast\nendfor\n```\n\nIt works with nested list:\n\n```\nlet meals = [[\"breakfast\", \"pancakes\"], [\"lunch\", \"fish\"], [\"dinner\", \"pasta\"]]\n\nfor [meal_type, food] in meals\n  echo \"I am having \" . food . \" for \" . meal_type\nendfor\n```\n\nYou can technically use the `for` loop with a dictionary using the `keys()` method.\n\n```\nlet beverages = #{breakfast: \"milk\", lunch: \"orange juice\", dinner: \"water\"}\nfor beverage_type in keys(beverages)\n  echo \"I am drinking \" . beverages[beverage_type] . \" for \" . beverage_type\nendfor\n```\n\n## While\n\nAnother common loop is the `while` loop.\n\n```\nlet counter = 1\nwhile counter < 5\n  echo \"Counter is: \" . counter\n  let counter += 1\nendwhile\n```\n\nTo get the content of the current line to the last line:\n\n```\nlet current_line = line(\".\")\nlet last_line = line(\"$\")\n\nwhile current_line <= last_line\n  echo getline(current_line)\n  let current_line += 1\nendwhile\n```\n\n## Error Handling\n\nOften your program doesn't run the way you expect it to. As a result, it throws you for a loop (pun intended). What you need is a proper error handling.\n\n### Break\n\nWhen you use `break` inside a `while` or `for` loop, it stops the loop.\n\nTo get the texts from the start of the file to the current line, but stop when you see the word \"donut\":\n\n```\nlet line = 0\nlet last_line = line(\"$\")\nlet total_word = \"\"\n\nwhile line <= last_line\n  let line += 1\n  let line_text = getline(line)\n  if line_text =~# \"donut\"\n    break\n  endif\n  echo line_text\n  let total_word .= line_text . \" \"\nendwhile\n\necho total_word\n```\n\nIf you have the text:\n\n```\none\ntwo\nthree\ndonut\nfour\nfive\n```\n\nRunning the above `while` loop gives \"one two three\" and not the rest of the text because the loop breaks once it matches \"donut\".\n\n### Continue\n\nThe `continue` method is similar to `break`, where it is invoked during a loop. The difference is that instead of breaking out of the loop, it just skips that current iteration.\n\nSuppose you have the same text but instead of `break`, you use `continue`:\n\n```\nlet line = 0\nlet last_line = line(\"$\")\nlet total_word = \"\"\n\nwhile line <= last_line\n  let line += 1\n  let line_text = getline(line)\n  if line_text =~# \"donut\"\n    continue\n  endif\n  echo line_text\n  let total_word .= line_text . \" \"\nendwhile\n\necho total_word\n```\n\nThis time it returns `one two three four five`. It skips the line with the word \"donut\", but the loop continues.\n\n### try, finally, and catch\n\nVim has a `try`, `finally`, and `catch` to handle errors. To simulate an error, you can use the `throw` command.\n\n```\ntry\n  echo \"Try\"\n  throw \"Nope\"\nendtry\n```\n\nRun this. Vim will complain with `\"Exception not caught: Nope` error.\n\nNow add a catch block:\n\n```\ntry\n  echo \"Try\"\n  throw \"Nope\"\ncatch\n  echo \"Caught it\"\nendtry\n```\n\nNow there is no longer any error. You should see \"Try\" and \"Caught it\" displayed.\n\nLet's remove the `catch` and add a `finally`:\n\n```\ntry\n  echo \"Try\"\n  throw \"Nope\"\n  echo \"You won't see me\"\nfinally\n  echo \"Finally\"\nendtry\n```\n\nRun this. Now Vim displays the error and \"Finally\".\n\nLet's put all of them together:\n\n```\ntry\n  echo \"Try\"\n  throw \"Nope\"\ncatch\n  echo \"Caught it\"\nfinally\n  echo \"Finally\"\nendtry\n```\n\nThis time Vim displays both \"Caught it\" and \"Finally\". No error is displayed because Vim caught it.\n\nErrors come from different places. Another source of error is calling a nonexistent function, like `Nope()` below:\n\n```\ntry\n  echo \"Try\"\n  call Nope()\ncatch\n  echo \"Caught it\"\nfinally\n  echo \"Finally\"\nendtry\n```\n\nThe difference between `catch` and `finally` is that `finally` is always run, error or not, whereas `catch` is only run when your code gets an error.\n\nYou can catch specific error with `:catch`. According to `:h :catch`:\n\n```\ncatch /^Vim:Interrupt$/.             \" catch interrupts (CTRL-C)\ncatch /^Vim\\\\%((\\\\a\\\\+)\\\\)\\\\=:E/.    \" catch all Vim errors\ncatch /^Vim\\\\%((\\\\a\\\\+)\\\\)\\\\=:/.     \" catch errors and interrupts\ncatch /^Vim(write):/.                \" catch all errors in :write\ncatch /^Vim\\\\%((\\\\a\\\\+)\\\\)\\\\=:E123:/ \" catch error E123\ncatch /my-exception/.                \" catch user exception\ncatch /.*/                           \" catch everything\ncatch.                               \" same as /.*/\n```\n\nInside a `try` block, an interrupt is considered a catchable error.\n\n```\ntry\n  catch /^Vim:Interrupt$/\n  sleep 100\nendtry\n```\n\nIn your vimrc, if you use a custom colorscheme, like [gruvbox](https://github.com/morhetz/gruvbox), and you accidentally delete the colorscheme directory but still have the line `colorscheme gruvbox` in your vimrc, Vim will throw an error when you `source` it. To fix this, I added this in my vimrc:\n\n```\ntry\n  colorscheme gruvbox\ncatch\n  colorscheme default\nendtry\n```\n\nNow if you `source` vimrc without `gruvbox` directory, Vim will use the `colorscheme default`.\n\n## Learn Conditionals the Smart Way\n\nIn the previous chapter, you learned about Vim basic data types. In this chapter, you learned how to combine them to write basic programs using conditionals and loops. These are the building blocks of programming.\n\nNext, let's learn about variable scopes.\n\n## Link\n- Prev [Ch25. Vimscript Basic Data Types](./ch25_vimscript_basic_data_types.md)\n- Next [Ch27. Vimscript Variable Scopes](./ch27_vimscript_variable_scopes.md)\n"
  },
  {
    "path": "ch27_vimscript_variable_scopes.md",
    "content": "# Ch27. Vimscript Variable Scopes\n\nBefore diving into Vimscript functions, let's learn about the different sources and scopes of Vim variables.\n\n## Mutable and Immutable Variables\n\nYou can assign a value to a variable in Vim with `let`:\n\n```\nlet pancake = \"pancake\"\n```\n\nLater you can call that variable any time.\n\n```\necho pancake\n\" returns \"pancake\"\n```\n\n`let` is mutable, meaning you can change the value at any time in the future.\n\n```\nlet pancake = \"pancake\"\nlet pancake = \"not waffles\"\n\necho pancake\n\" returns \"not waffles\"\n```\n\nNotice that when you want to change the value of a set variable, you still need to use `let`.\n\n```\nlet beverage = \"milk\"\n\nbeverage = \"orange juice\"\n\" throws an error\n```\n\nYou can define an immutable variable with `const`. Being immutable, once a variable value is assigned, you cannot reassign it with a different value.\n\n```\nconst waffle = \"waffle\"\nconst waffle = \"pancake\"\n\" throws an error\n```\n\n## Variable Sources\n\nThere are three sources for variables: environment variable, option variable, and register variable.\n\n### Environment Variable\n\nVim can access your terminal environment variable. For example, if you have the `SHELL` environment variable available in your terminal, you can access it from Vim with:\n\n```\necho $SHELL\n\" returns $SHELL value. In my case, it returns /bin/bash\n```\n\n### Option Variable\n\nYou can access Vim options with `&` (these are the settings you access with `set`).\n\nFor example, to see what background Vim uses, you can run:\n\n```\necho &background\n\" returns either \"light\" or \"dark\"\n```\n\nAlternatively, you can always run `set background?` to see the value of the `background` option.\n\n### Register Variable\n\nYou can access Vim registers (Ch. 08) with `@`.\n\nSuppose the value \"chocolate\" is already saved in register a. To access it, you can use `@a`. You can also update it with `let`.\n\n```\necho @a\n\" returns chocolate\n\nlet @a .= \" donut\"\n\necho @a\n\" returns \"chocolate donut\"\n```\n\nNow when you paste from register `a` (`\"ap`), it will return \"chocolate donut\". The operator `.=` concatenates two strings. The expression `let @a .= \" donut\"` is the same as `let @a = @a . \" donut\"`\n\n## Variable Scopes\n\nThere are 9 different variable scopes in Vim. You can recognize them from their prepended letter:\n\n```\ng:           Global variable\n{nothing}    Global variable\nb:           Buffer-local variable\nw:           Window-local variable\nt:           Tab-local variable\ns:           Sourced Vimscript variable\nl:           Function local variable\na:           Function formal parameter variable\nv:           Built-in Vim variable\n```\n\n### Global Variable\n\nWhen you are declaring a \"regular\" variable:\n\n```\nlet pancake = \"pancake\"\n```\n\n`pancake` is actually a global variable. When you define a global variable, you can call them from anywhere.\n\nPrepending `g:` to a variable also creates a global variable.\n\n```\nlet g:waffle = \"waffle\"\n```\n\nIn this case both `pancake` and `g:waffle` have the same scope. You can call each of them with or without `g:`.\n\n```\necho pancake\n\" returns \"pancake\"\n\necho g:pancake\n\" returns \"pancake\"\n\necho waffle\n\" returns \"waffle\"\n\necho g:waffle\n\" returns \"waffle\"\n```\n\n### Buffer Variable\n\nA variable preceded with `b:` is a buffer variable. A buffer variable is a variable that is local to the current buffer (Ch. 02). If you have multiple buffers open, each buffer will have their own separate list of buffer variables.\n\nIn buffer 1:\n\n```\nconst b:donut = \"chocolate donut\"\n```\n\nIn buffer 2:\n\n```\nconst b:donut = \"blueberry donut\"\n```\n\nIf you run `echo b:donut` from buffer 1, it will return \"chocolate donut\". If you run it from buffer 2, it will return \"blueberry donut\".\n\nOn the side note, Vim has a *special* buffer variable `b:changedtick` that keeps track of all the changes done to the current buffer.\n\n1. Run `echo b:changedtick` and note the number it returns..\n2. Make changes in Vim.\n3. Run `echo b:changedtick` again and note the number it now returns.\n\n### Window Variable\n\nA variable preceded with `w:` is a window variable. It exists only in that window.\n\nIn window 1:\n\n```\nconst w:donut = \"chocolate donut\"\n```\n\nIn window 2:\n\n```\nconst w:donut = \"raspberry donut\"\n```\n\nOn each window, you can call `echo w:donut` to get unique values.\n\n### Tab Variable\n\nA variable preceded with `t:` is a tab variable. It exists only in that tab.\n\nIn tab 1:\n\n```\nconst t:donut = \"chocolate donut\"\n```\n\nIn tab 2:\n\n```\nconst t:donut = \"blackberry donut\"\n```\n\nOn each tab, you can call `echo t:donut` to get unique values.\n\n### Script Variable\n\nA variable preceded with `s:` is a script variable. These variables can only be accessed from inside that script.\n\nIf you have an arbitrary file `dozen.vim` and inside it you have:\n\n```\nlet s:dozen = 12\n\nfunction Consume()\n  let s:dozen -= 1\n  echo s:dozen \" is left\"\nendfunction\n```\n\nSource the file with `:source dozen.vim`. Now call the `Consume` function:\n\n```\n:call Consume()\n\" returns \"11 is left\"\n\n:call Consume()\n\" returns \"10 is left\"\n\n:echo s:dozen\n\" Undefined variable error\n```\n\nWhen you call `Consume`, you see it decrements the `s:dozen` value as expected. When you try to get `s:dozen` value directly, Vim won't find it because you are out of scope. `s:dozen` is only accessible from inside `dozen.vim`.\n\nEach time you source the `dozen.vim` file, it resets the `s:dozen` counter. If you are in the middle of decrementing `s:dozen` value and you run `:source dozen.vim`, the counter resets back to 12. This can be a problem for unsuspecting users. To fix this issue, refactor the code:\n\n```\nif !exists(\"s:dozen\")\n  let s:dozen = 12\nendif\n\nfunction Consume()\n  let s:dozen -= 1\n  echo s:dozen\nendfunction\n```\n\nNow when you source `dozen.vim` while in the middle of decrementing, Vim reads `!exists(\"s:dozen\")`, finds that it is true, and doesn't reset the value back to 12.\n\n### Function Local and Function Formal Parameter Variable\n\nBoth the function local variable (`l:`) and the function formal variable (`a:`) will be covered in the next chapter.\n\n### Built-in Vim Variables\n\nA variable prepended with `v:` is a special built-in Vim variable. You cannot define these variables. You have seen some of them already.\n- `v:version` tells you what Vim version you are using.\n- `v:key` contains the current item value when iterating through a dictionary.\n- `v:val` contains the current item value when running a `map()` or `filter()` operation.\n- `v:true`, `v:false`, `v:null`, and `v:none` are special data types.\n\nThere are other variables. For a list of Vim built-in variables, check out `:h vim-variable` or `:h v:`.\n\n## Using Vim Variable Scopes the Smart Way\n\nBeing able to quickly access environment, option, and register variables give you a broad flexibility to customize your editor and terminal environment. You also learned that Vim has 9 different variable scopes, each existing under a certain constraints. You can take advantage of these unique variable types to decouple your program.\n\nYou made it this far. You learned about data types, means of combinations, and variable scopes. Only one thing is left: functions.\n\n## Link\n- Prev [Ch26. Vimscript Conditionals and Loops](./ch26_vimscript_conditionals_and_loops.md)\n- Next [Ch28. Vimscript Functions](./ch28_vimscript_functions.md)\n"
  },
  {
    "path": "ch28_vimscript_functions.md",
    "content": "# Ch28. Vimscript Functions\n\nFunctions are means of abstraction, the third element in learning a new language.\n\nIn the previous chapters, you have seen Vimscript native functions (`len()`, `filter()`, `map()`, etc.) and custom functions in action. In this chapter, you will go deeper to learn how functions work.\n\n## Function Syntax Rules\n\nAt the core, a Vimscript function has the following syntax:\n\n```\nfunction {FunctionName}()\n  {do-something}\nendfunction\n```\n\nA function definition must start with a capital letter. It starts with the `function` keyword and ends with `endfunction`. Below is a valid function:\n\n```\nfunction! Tasty()\n  echo \"Tasty\"\nendfunction\n```\n\nThe following is not a valid function because it does not start with a capital letter.\n\n```\nfunction tasty()\n  echo \"Tasty\"\nendfunction\n```\n\nIf you prepend a function with the script variable (`s:`), you can use it with a lower case. `function s:tasty()` is a valid name. The reason why Vim requires you to use an uppercase name is to prevent confusion with Vim's built-in functions (all lowercase).\n\nA function name cannot start with a number. `1Tasty()` is not a valid function name, but `Tasty1()` is. A function also cannot contain non-alphanumeric characters besides `_`. `Tasty-food()`, `Tasty&food()`, and `Tasty.food()` are not valid function names. `Tasty_food()` *is*.\n\nIf you define two functions with the same name, Vim will throw an error complaining that the function `Tasty` already exists. To overwrite the previous function with the same name, add a `!` after the `function` keyword.\n\n```\nfunction! Tasty()\n  echo \"Tasty\"\nendfunction\n```\n\n## Listing Available Functions\n\nTo see all the built-in and custom functions in Vim, you can run `:function` command. To look at the content of the `Tasty` function, you can run `:function Tasty`.\n\nYou can also search for functions with pattern with `:function /pattern`, similar to Vim's search navigation (`/pattern`). To search for all function containing the phrase \"map\", run `:function /map`. If you use external plugins, Vim will display the functions defined in those plugins.\n\nIf you want to look at where a function originates, you can use the `:verbose` command with the `:function` command. To look at where all the functions containing the word \"map\" are originated, run:\n\n```\n:verbose function /map\n```\n\nWhen I ran it, I got a number of results. This one tells me that the function `fzf#vim#maps` autoload function (to recap, refer to Ch. 23) is written inside `~/.vim/plugged/fzf.vim/autoload/fzf/vim.vim` file, on line 1263. This is useful for debugging.\n\n```\nfunction fzf#vim#maps(mode, ...)\n        Last set from ~/.vim/plugged/fzf.vim/autoload/fzf/vim.vim line 1263\n```\n\n## Removing a Function\n\nTo remove an existing function, use `:delfunction {Function_name}`. To delete `Tasty`, run `:delfunction Tasty`.\n\n## Function Return Value\n\nFor a function to return a value, you need to pass it an explicit `return` value. Otherwise, Vim automatically returns an implicit value of 0.\n\n```\nfunction! Tasty()\n  echo \"Tasty\"\nendfunction\n```\n\nAn empty `return` is also equivalent to a 0 value.\n\n```\nfunction! Tasty()\n  echo \"Tasty\"\n  return\nendfunction\n```\n\nIf you run `:echo Tasty()` using the function above, after Vim displays \"Tasty\", it returns 0, the implicit return value. To make `Tasty()` to return \"Tasty\" value, you can do this:\n\n```\nfunction! Tasty()\n  return \"Tasty\"\nendfunction\n```\n\nNow when you run `:echo Tasty()`, it returns \"Tasty\" string.\n\nYou can use a function inside an expression. Vim will use the return value of that function. The expression `:echo Tasty() . \" Food!\"` outputs \"Tasty Food!\"\n\n## Formal Arguments\n\nTo pass a formal argument `food` to your `Tasty` function, you can do this:\n\n```\nfunction! Tasty(food)\n  return \"Tasty \" . a:food\nendfunction\n\necho Tasty(\"pastry\")\n\" returns \"Tasty pastry\"\n```\n\n`a:` is one of the variable scopes mentioned in the last chapter. It is the formal parameter variable. It is Vim's way to get a formal parameter value in a function. Without it, Vim will throw an error:\n\n```\nfunction! Tasty(food)\n  return \"Tasty \" . food\nendfunction\n\necho Tasty(\"pasta\")\n\" returns \"undefined variable name\" error\n```\n\n## Function Local Variable\n\nLet's address the other variable you didn't learn on the previous chapter: the function local variable (`l:`).\n\nWhen writing a function, you can define a variable inside:\n\n```\nfunction! Yummy()\n  let location = \"tummy\"\n  return \"Yummy in my \" . location\nendfunction\n\necho Yummy()\n\" returns \"Yummy in my tummy\"\n```\n\nIn this context, the variable `location` is the same as `l:location`. When you define a variable in a function, that variable is *local* to that function. When a user sees `location`, it could easily be mistaken as a global variable. I prefer to be more verbose than not, so I prefer to put `l:` to indicate that this is a function variable.\n\nAnother reason to use `l:count` is that Vim has special variables with aliases that look like regular variables. `v:count` is one example. It has an alias of `count`. In Vim, calling `count` is the same as calling `v:count`. It is easy to accidentally call one of those special variables.\n\n```\nfunction! Calories()\n  let count = \"count\"\n  return \"I do not \" . count . \" my calories\"\nendfunction\n\necho Calories()\n\" throws an error\n```\n\nThe execution above throws an error because `let count = \"Count\"` implicitly attempts to redefine Vim's special variable `v:count`. Recall that special variables (`v:`) are read-only. You cannot mutate it. To fix it, use `l:count`:\n\n```\nfunction! Calories()\n  let l:count = \"count\"\n  return \"I do not \" . l:count . \" my calories\"\nendfunction\n\necho Calories()\n\" returns \"I do not count my calories\"\n```\n\n## Calling a Function\n\nVim has a `:call` command to call a function.\n\n```\nfunction! Tasty(food)\n  return \"Tasty \" . a:food\nendfunction\n\ncall Tasty(\"gravy\")\n```\n\nThe `call` command does not output the return value. Let's call it with `echo`.\n\n```\necho call Tasty(\"gravy\")\n```\n\nWoops, you get an error. The `call` command above is a command-line command (`:call`). The `echo` command above is also a command-line command (`:echo`). You cannot call a command-line command with another command-line command. Let's try a different flavor of the `call` command:\n\n```\necho call(\"Tasty\", [\"gravy\"])\n\" returns \"Tasty gravy\"\n```\n\nTo clear any confusion, you have just used two different `call` commands: the `:call` command-line command and the `call()` function. The `call()` function accepts as its first argument the function name (string) and its second argument the formal parameters (list). \n\nTo learn more about `:call` and `call()`, check out `:h call()` and `:h :call`.\n\n## Default Argument\n\nYou can provide a function parameter with a default value with `=`. If you call `Breakfast` with only one argument, the `beverage` argument will use the \"milk\" default value.\n\n```\nfunction! Breakfast(meal, beverage = \"Milk\")\n  return \"I had \" . a:meal . \" and \" . a:beverage . \" for breakfast\"\nendfunction\n\necho Breakfast(\"Hash Browns\")\n\" returns I had hash browns and milk for breakfast\n\necho Breakfast(\"Cereal\", \"Orange Juice\")\n\" returns I had Cereal and Orange Juice for breakfast\n```\n\n## Variable Arguments\n\nYou can pass a variable argument with three-dots (`...`). Variable argument is useful when you don't know how many variables a user will give.\n\nSuppose you are creating an all-you-can-eat buffet (you'll never know how much food your customer will eat):\n\n```\nfunction! Buffet(...)\n  return a:1\nendfunction\n```\n\nIf you run `echo Buffet(\"Noodles\")`, it will output \"Noodles\". Vim uses `a:1` to print the *first* argument passed to `...`, up to 20 (`a:1` is the first argument, `a:2` is the second argument, etc). If you run `echo Buffet(\"Noodles\", \"Sushi\")`, it will still display just \"Noodles\", let's update it:\n\n```\nfunction! Buffet(...)\n  return a:1 . \" \" . a:2\nendfunction\n\necho Buffet(\"Noodles\", \"Sushi\")\n\" returns \"Noodles Sushi\"\n```\n\nThe problem with this approach is if you now run `echo Buffet(\"Noodles\")` (with only one variable), Vim complains that it has an undefined variable `a:2`. How can you make it flexible enough to display exactly what the user gives?\n\nLuckily, Vim has a special variable `a:0` to display the *number* of the arguments passed into `...`.\n\n```\nfunction! Buffet(...)\n  return a:0\nendfunction\n\necho Buffet(\"Noodles\")\n\" returns 1\n\necho Buffet(\"Noodles\", \"Sushi\")\n\" returns 2\n\necho Buffet(\"Noodles\", \"Sushi\", \"Ice cream\", \"Tofu\", \"Mochi\")\n\" returns 5\n```\n\nWith this, you can iterate using the length of the argument.\n\n```\nfunction! Buffet(...)\n  let l:food_counter = 1\n  let l:foods = \"\"\n  while l:food_counter <= a:0\n    let l:foods .= a:{l:food_counter} . \" \"\n    let l:food_counter += 1\n  endwhile\n  return l:foods\nendfunction\n```\n\nThe curly braces `a:{l:food_counter}` is a string interpolation, it uses the value of `food_counter` counter to call the formal parameter arguments `a:1`, `a:2`, `a:3`, etc.\n\n```\necho Buffet(\"Noodles\")\n\" returns \"Noodles\"\n\necho Buffet(\"Noodles\", \"Sushi\", \"Ice cream\", \"Tofu\", \"Mochi\")\n\" returns everything you passed: \"Noodles Sushi Ice cream Tofu Mochi\"\n```\n\nThe variable argument has one more special variable: `a:000`. It has the value of all variable arguments in a list format.\n\n```\nfunction! Buffet(...)\n  return a:000\nendfunction\n\necho Buffet(\"Noodles\")\n\" returns [\"Noodles\"]\n\necho Buffet(\"Noodles\", \"Sushi\", \"Ice cream\", \"Tofu\", \"Mochi\")\n\" returns [\"Noodles\", \"Sushi\", \"Ice cream\", \"Tofu\", \"Mochi\"]\n```\n\nLet's refactor the function to use a `for` loop:\n\n```\nfunction! Buffet(...)\n  let l:foods = \"\"\n  for food_item in a:000\n    let l:foods .= food_item . \" \"\n  endfor\n  return l:foods\nendfunction\n\necho Buffet(\"Noodles\", \"Sushi\", \"Ice cream\", \"Tofu\", \"Mochi\")\n\" returns Noodles Sushi Ice cream Tofu Mochi\n```\n\n## Range\n\nYou can define a *ranged* Vimscript function by adding a `range` keyword at the end of the function definition. A ranged function has two special variables available: `a:firstline` and `a:lastline`.\n\n```\nfunction! Breakfast() range\n  echo a:firstline\n  echo a:lastline\nendfunction\n```\n\nIf you are on line 100 and you run `call Breakfast()`, it will display 100 for both `firstline` and `lastline`. If you visually highlight (`v`, `V`, or `Ctrl-V`) lines 101 to 105 and run `call Breakfast()`, `firstline` displays 101 and `lastline` displays 105. `firstline` and `lastline` displays the minimum and maximum range where the function is called.\n\nYou can also use `:call` and passing it a range. If you run `:11,20call Breakfast()`, it will display 11 for `firstline` and 20 for `lastline`.\n\nYou might ask, \"That's nice that Vimscript function accepts range, but can't I get the line number with `line(\".\")`? Won't it do the same thing?\"\n\nGood question. If this is what you mean:\n\n```\nfunction! Breakfast()\n  echo line(\".\")\nendfunction\n```\n\nCalling `:11,20call Breakfast()` executes the `Breakfast` function 10 times (one for each line in the range). Compare that if you had passed the `range` argument:\n\n```\nfunction! Breakfast() range\n  echo line(\".\")\nendfunction\n```\n\nCalling `11,20call Breakfast()` executes the `Breakfast` function *once*.\n\nIf you pass a `range` keyword and you pass a numerical range (like `11,20`) on `call`, Vim only executes that function once. If you don't pass a `range` keyword and you pass a numerical range (like `11,20`) on `call`, Vim executes that function N times depending on the range (in this case, N = 10).\n\n## Dictionary\n\nYou can add a function as a dictionary item by adding a `dict` keyword when defining a function.\n\nIf you have a function `SecondBreakfast` that returns whatever `breakfast` item you have:\n\n```\nfunction! SecondBreakfast() dict\n  return self.breakfast\nendfunction\n```\n\nLet's add this function to the `meals` dictionary:\n\n```\nlet meals = {\"breakfast\": \"pancakes\", \"second_breakfast\": function(\"SecondBreakfast\"), \"lunch\": \"pasta\"}\n\necho meals.second_breakfast()\n\" returns \"pancakes\"\n```\n\nWith `dict` keyword, the key variable `self` refers to the dictionary where the function is stored (in this case, the `meals` dictionary). The expression `self.breakfast` is equal to `meals.breakfast`.\n\nAn alternative way to add a function into a dictionary object is to use a namespace.\n\n```\nfunction! meals.second_lunch()\n  return self.lunch\nendfunction\n\necho meals.second_lunch()\n\" returns \"pasta\"\n```\n\nWith namespace, you do not have to use the `dict` keyword.\n\n## Funcref\n\nA funcref is a reference to a function. It is one of Vimscript's basic data types mentioned in Ch. 24.\n\nThe expression `function(\"SecondBreakfast\")` above is an example of funcref. Vim has a built-in function `function()` that returns a funcref when you pass it a function name (string).\n\n```\nfunction! Breakfast(item)\n  return \"I am having \" . a:item . \" for breakfast\"\nendfunction\n\nlet Breakfastify = Breakfast\n\" returns error\n\nlet Breakfastify = function(\"Breakfast\")\n\necho Breakfastify(\"oatmeal\")\n\" returns \"I am having oatmeal for breakfast\"\n\necho Breakfastify(\"pancake\")\n\" returns \"I am having pancake for breakfast\"\n```\n\nIn Vim, if you want to assign a function to a variable, you can't just run assign it directly like `let MyVar = MyFunc`. You need to use the `function()` function, like `let MyVar = function(\"MyFunc\")`.\n\nYou can use funcref with maps and filters. Note that maps and filters will pass an index as the first argument and the iterated value as the second argument.\n\n```\nfunction! Breakfast(index, item)\n  return \"I am having \" . a:item . \" for breakfast\"\nendfunction\n\nlet breakfast_items = [\"pancakes\", \"hash browns\", \"waffles\"]\nlet first_meals = map(breakfast_items, function(\"Breakfast\"))\n\nfor meal in first_meals\n  echo meal\nendfor\n```\n\n## Lambda\n\nA better way to use functions in maps and filters is to use lambda expression (sometimes known as unnamed function). For example:\n\n```\nlet Plus = {x,y -> x + y}\necho Plus(1,2)\n\" returns 3\n\nlet Tasty = { -> 'tasty'}\necho Tasty()\n\" returns \"tasty\"\n```\n\nYou can call a function from inside a lambda expression:\n\n```\nfunction! Lunch(item)\n  return \"I am having \" . a:item . \" for lunch\"\nendfunction\n\nlet lunch_items = [\"sushi\", \"ramen\", \"sashimi\"]\n\nlet day_meals = map(lunch_items, {index, item -> Lunch(item)})\n\nfor meal in day_meals\n  echo meal\nendfor\n```\n\nIf you don't want to call the function from inside lambda, you can refactor it:\n\n```\nlet day_meals = map(lunch_items, {index, item -> \"I am having \" . item . \" for lunch\"})\n```\n\n## Method Chaining\n\nYou can chain several Vimscript functions and lambda expressions sequentially with `->`. Keep in mind that `->` must be followed by a method name *without space.*\n\n```\nSource->Method1()->Method2()->...->MethodN()\n```\n\nTo convert a float to a number using method chaining:\n\n```\necho 3.14->float2nr()\n\" returns 3\n```\n\nLet's do a more complicated example. Suppose that you need to capitalize the first letter of each item on a list, then sort the list, then join the list to form a string.\n\n```\nfunction! Capitalizer(word)\n  return substitute(a:word, \"\\^\\.\", \"\\\\u&\", \"g\")\nendfunction\n\nfunction! CapitalizeList(word_list)\n  return map(a:word_list, {index, word -> Capitalizer(word)})\nendfunction\n\nlet dinner_items = [\"bruschetta\", \"antipasto\", \"calzone\"]\n\necho dinner_items->CapitalizeList()->sort()->join(\", \")\n\" returns \"Antipasto, Bruschetta, Calzone\"\n```\n\nWith method chaining, the sequence is more easily read and understood. I can just glance at `dinner_items->CapitalizeList()->sort()->join(\", \")` and know exactly what is going on.\n\n## Closure\n\nWhen you define a variable inside a function, that variable exists within that function boundaries. This is called a lexical scope.\n\n```\nfunction! Lunch()\n  let appetizer = \"shrimp\"\n\n  function! SecondLunch()\n    return appetizer\n  endfunction\n\n  return funcref(\"SecondLunch\")\nendfunction\n```\n\n`appetizer` is defined inside the `Lunch` function, which returns `SecondLunch` funcref. Notice that `SecondLunch` uses the `appetizer`, but in Vimscript, it doesn't have access to that variable. If you try to run `echo Lunch()()`, Vim will throw an undefined variable error.\n\nTo fix this issue, use the `closure` keyword. Let's refactor:\n\n```\nfunction! Lunch()\n  let appetizer = \"shrimp\"\n\n  function! SecondLunch() closure\n    return appetizer\n  endfunction\n\n  return funcref(\"SecondLunch\")\nendfunction\n```\n\nNow if you run `echo Lunch()()`, Vim will return \"shrimp\".\n\n## Learn Vimscript Functions the Smart Way\n\nIn this chapter, you learned the anatomy of Vim function. You learned how to use different special keywords `range`, `dict`, and `closure` to modify function behavior. You also learned how to use lambda and to chain multiple functions together. Functions are important tools for creating complex abstractions.\n\nNext, let's put everything that you have learned together to make your own plugin.\n\n## Link\n- Prev [Ch27. Vimscript Variable Scopes](./ch27_vimscript_variable_scopes.md)\n- Next [Ch29. Write a Plugin: Creating a Titlecase Operator](./ch29_plugin_example_writing-a-titlecase-plugin.md)\n"
  },
  {
    "path": "ch29_plugin_example_writing-a-titlecase-plugin.md",
    "content": "# Ch29. Write a Plugin: Creating a Titlecase Operator\n\nWhen you start to get good at Vim, you may want to write your own plugins. I recently wrote my first Vim plugin, [totitle-vim](https://github.com/iggredible/totitle-vim). It is a titlecase operator plugin, akin to Vim's uppercase `gU`, lowercase `gu`, and togglecase `g~` operators.\n\nIn this chapter, I will present the breakdown of the `totitle-vim` plugin. I hope to shed some light on the process and maybe inspire you to create your own unique plugin!\n\n## The Problem\n\nI use Vim to write my articles, including this very guide.\n\nOne main issue was to create a proper title case for the headings. One way to automate this is to capitalize each word in the header with `g/^#/ s/\\<./\\u\\0/g`. For basic use, this command was good enough, but it is still not as good as having an actual title case. The words \"The\" and \"Of\" in \"Capitalize The First Letter Of Each Word\" should be capitalized. Without a proper capitalization, the sentence looks slightly off.\n\nAt first, I wasn't planning to write a plugin. Also it turns out that there is a titlecase plugin already: [vim-titlecase](https://github.com/christoomey/vim-titlecase). However, there were a few things that didn't function quite the way I wanted them to. The main one was the blockwise visual mode behavior. If I have the phrase:\n\n```\ntest title one\ntest title two\ntest title three\n```\n\nIf I use a block visual highlight on the \"tle\":\n\n```\ntest ti[tle] one\ntest ti[tle] two\ntest ti[tle] three\n```\n\nIf I press `gt`, the plugin won't capitalize it. I find it inconsistent with the behaviors of `gu`, `gU`, and `g~`. So I decided to work off from that titlecase plugin repo and use that to create a titlecase plugin myself that is consistent with `gu`, `gU`, and `g~`! Again, the vim-titlecase plugin itself is an excellent plugin and worthy to be used on its own (the truth is, maybe deep down I just wanted to write my own Vim plugin. I can't really see the blockwise titlecasing feature to be used that often in real life other than edge cases).\n\n### Planning for the Plugin\n\nBefore writing the first line of code, I need to decide what the titlecase rules are. I found a neat table of different capitalization rules from the [titlecaseconverter site](https://titlecaseconverter.com/rules/). Did you know that there are at least 8 different capitalization rules in English language? *Gasp!*\n\nIn the end, I used the common denominators from that list to come up with a good enough basic rule for the plugin. Plus I doubt people will complain, \"Hey man, you're using AMA, why aren't you using APA?\". Here are the basic rules:\n- First word is always uppercased.\n- Some adverbs, conjunctions, and prepositions are lowercased.\n- If the input word is totally uppercased, then don't do anything (it could be an abbreviation).\n\nAs for which words are lowercased, different rules have different lists. I decided to stick with `a an and at but by en for in nor of off on or out per so the to up yet vs via`.\n\n### Planning for the User Interface\n\nI want the plugin to be an operator to complement Vim's existing case operators: `gu`, `gU`, and `g~`. Being an operator, it must accept either a motion or a text object (`gtw` should titlecase the next word, `gtiw` should titlecase the inner word, `gt$` should titlecase the words from the current location until the end of the line, `gtt` should titlecase the current line, `gti(` should titlecase the words inside parentheses, etc). I also want it to be mapped to `gt` for easy mnemonics. Moreover, it should also work with all visual modes: `v`, `V`, and `Ctrl-V`. I should be able to highlight it in *any* visual mode, press `gt`, then all the highlighted texts will be titlecased.\n\n## Vim Runtime\n\nThe first thing you see when you look at the repo is that it has two directories: `plugin/` and `doc/`. When you start Vim, it looks for special files and directories inside the `~/.vim` directory and runs all script files inside that directory. For more, review the Vim Runtime chapter.\n\nThe plugin utilizes two Vim runtime directories: `doc/` and `plugin/`. `doc/` is a place to put the help documentation (so you can search for keywords later, like `:h totitle`). I'll go over how to create a help page later. For now, let's focus on `plugin/`. The `plugin/` directory is executed once when Vim boots up. There is one file inside this directory: `totitle.vim`. The naming doesn't matter (I could've named it `whatever.vim` and it would still work). All the code responsible for the plugin to work is inside this file.\n\n## Mappings\n\nLet's go through the code! \n\nAt the start of the file, you have:\n\n```\nif !exists('g:totitle_default_keys')\n  let g:totitle_default_keys = 1\nendif\n```\n\nWhen you start Vim, `g:totitle_default_keys` won't exist yet, so `!exists(...)` returns true. In that case, define `g:totitle_default_keys` to equal 1. In Vim, 0 is falsy and non-zero is truthy (use 1 to indicate truthy).\n\nLet's jump to the bottom of the file. You'll see this:\n\n```\nif g:totitle_default_keys\n  nnoremap <expr> gt ToTitle()\n  xnoremap <expr> gt ToTitle()\n  nnoremap <expr> gtt ToTitle() .. '_'\nendif\n```\n\nThis is where the main `gt` mapping is defined. In this case, by the time you get to the `if` conditionals at the bottom of the file, `if g:totitle_default_keys` would return 1 (truthy), so Vim performs the following maps:\n- `nnoremap <expr> gt ToTitle()` maps the normal mode *operator*. This lets you run operator + motion/text-object like `gtw` to titlecase the next word or `gtiw` to titlecase the inner word. I will go over the details of how the operator mapping works later.\n- `xnoremap <expr> gt ToTitle()` maps the visual mode operators. This lets you to titlecase the texts that are visually highlighted.\n- `nnoremap <expr> gtt ToTitle() .. '_'` maps the normal mode linewise operator (analogous to `guu` and `gUU`). You may wonder what `.. '_'` does at the end. `..` is Vim's string interpolation operator. `_` is used as a motion with an operator. If you look in `:help _`, it says that the underscore is used to count 1 line downward. It performs an operator on the current line (try it with other operators, try running `gU_` or `d_`, notice that it does the same as `gUU` or `dd`).\n- Finally, the `<expr>` argument allows you to specify the count, so you can do `3gtw` to togglecase the next 3 words.\n\nWhat if you don't want to use the default `gt` mapping? Afterall, you are overriding Vim's default `gt` (tab next) mapping. What if you want to use `gz` instead of `gt`? Remember earlier how you went through the trouble of checking `if !exists('g:totitle_default_keys')` and `if g:totitle_default_keys`? If you put `let g:totitle_default_keys = 0` in your vimrc, then `g:totitle_default_keys` would already exist when the plugin is run (codes in your vimrc are executed before the `plugin/` runtime files), so `!exists('g:totitle_default_keys')` returns false. Furthermore, `if g:totitle_default_keys` would be falsy (because it would have the value of 0), so it also won't perform the `gt` mapping! This effectively lets you define your own custom mapping in Vimrc.\n\nTo define your own titlecase mapping to `gz`, add this in your vimrc:\n\n```\nlet g:totitle_default_keys = 0\n\nnnoremap <expr> gz ToTitle()\nxnoremap <expr> gz ToTitle()\nnnoremap <expr> gzz ToTitle() .. '_'\n```\n\nEasy peasy.\n\n## The ToTitle Function\n\nThe `ToTitle()` function is easily the longest function in this file.\n\n```\n function! ToTitle(type = '')\n  if a:type ==# ''\n    set opfunc=ToTitle\n    return 'g@'\n  endif\n\n  \" invoke this when calling the ToTitle() function\n  if a:type != 'block' && a:type != 'line' && a:type != 'char'\n    let l:words = a:type\n    let l:wordsArr = trim(l:words)->split('\\s\\+')\n    call map(l:wordsArr, 's:capitalize(v:val)')\n    return l:wordsArr->join(' ')\n  endif\n\n  \" save the current settings\n  let l:sel_save = &selection\n  let l:reg_save = getreginfo('\"')\n  let l:cb_save = &clipboard\n  let l:visual_marks_save = [getpos(\"'<\"), getpos(\"'>\")]\n\n  try\n    set clipboard= selection=inclusive\n    let l:commands = #{line: \"'[V']y\", char: \"`[v`]y\", block: \"`[\\<c-v>`]y\"}\n\n    silent exe 'noautocmd keepjumps normal! ' .. get(l:commands, a:type, '')\n    let l:selected_phrase = getreg('\"')\n    let l:WORD_PATTERN = '\\<\\k*\\>'\n    let l:UPCASE_REPLACEMENT = '\\=s:capitalize(submatch(0))'\n\n    let l:startLine = line(\"'<\")\n    let l:startCol = virtcol(\".\")\n\n    \" when user calls a block operation\n    if a:type ==# \"block\"\n      sil! keepj norm! gv\"ad\n      keepj $\n      keepj pu_\n\n      let l:lastLine = line(\"$\")\n\n      sil! keepj norm \"ap\n\n      let l:curLine = line(\".\")\n\n      sil! keepj norm! VGg@\n      exe \"keepj norm! 0\\<c-v>G$h\\\"ad\"\n      exe \"keepj \" . l:startLine\n      exe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\\\"aP\"\n      exe \"keepj \" . l:lastLine\n      sil! keepj norm! \"_dG\n      exe \"keepj \" . l:startLine\n      exe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\"\n\n    \" when user calls a char or line operation\n    else\n      let l:titlecased = substitute(@@, l:WORD_PATTERN, l:UPCASE_REPLACEMENT, 'g')\n      let l:titlecased = s:capitalizeFirstWord(l:titlecased)\n      call setreg('\"', l:titlecased)\n      let l:subcommands = #{line: \"'[V']p\", char: \"`[v`]p\", block: \"`[\\<c-v>`]p\"}\n      silent execute \"noautocmd keepjumps normal! \" .. get(l:subcommands, a:type, \"\")\n      exe \"keepj \" . l:startLine\n      exe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\"\n    endif\n  finally\n\n    \" restore the settings\n    call setreg('\"', l:reg_save)\n    call setpos(\"'<\", l:visual_marks_save[0])\n    call setpos(\"'>\", l:visual_marks_save[1])\n    let &clipboard = l:cb_save\n    let &selection = l:sel_save\n  endtry\n  return\nendfunction\n```\n\nThis is very long, so let's break it apart. \n\n*I could refactor this into smaller sections, but for the sake of completing this chapter, I just left it as is.*\n\n## The Operator Function\n\nHere is the first part of the code:\n\n```\nif a:type ==# ''\n  set opfunc=ToTitle\n  return 'g@'\nendif\n```\n\nWhat the heck is `opfunc`? Why is it returning `g@`?\n\nVim has a special operator, the operator function, `g@`. This operator lets you to use *any* function assigned to the `opfunc` option. If I have the function `Foo()` assigned to `opfunc`, then when I run `g@w`, I am running `Foo()` on the next word. If I run `g@i(`, then I'm running `Foo()` on the inner parentheses. This operator function is critical to create your own Vim operator.\n\nThe following line assigns the `opfunc` to the `ToTitle` function.\n\n```\nset opfunc=ToTitle\n```\n\nThe next line is literally returning `g@`:\n\n```\nreturn g@\n```\n\nSo exactly how do these two lines work and why is it returning `g@`?\n\nLet's assume that you have the following map:\n\n```\nnnoremap <expr> gt ToTitle()\n```\n\nThen you press `gtw` (titlecase the next word). The first time you run `gtw`, Vim calls the `ToTitle()` method. But right now `opfunc` is still blank. You are also not passing any argument to `ToTitle()`, so it will have `a:type` value of `''`. This causes the conditional expression to check the argument `a:type`, `if a:type ==# ''`, to be truthy. Inside, you assign `opfunc` to the `ToTitle` function with `set opfunc=ToTitle`. Now `opfunc` is assigned to `ToTitle`. Finally, after you assigned `opfunc` to the `ToTitle` function, you return `g@`. I will explain why it returns `g@` below.\n\nYou are not done yet. Remember, you just pressed `gtw`. Pressing `gt` did all of the things above, but you still have `w` to process. By returning `g@`, at this point, you now technically have `g@w` (this is why you have `return g@`). Since `g@` is the function operator, you are passing to it the `w` motion. So Vim, upon receiving `g@w`, calls the `ToTitle` *one more time* (don't worry, you won't end up with an infinite loop as you will see in a little bit).\n\nTo recap, by pressing `gtw`, Vim checks if `opfunc` is empty or not. If it is empty, then Vim will assign it with `ToTitle`. Then it returns `g@`, essentially calling the `ToTitle` again one more time so you can now use it as an operator. This is the trickiest part of creating a custom operator and you did it! Next, you need to build the logic for `ToTitle()` to actually titlecase the input.\n\n## Processing the Input\n\nYou now have `gt` functioning as an operator that executes `ToTitle()`. But what do you do next? How do you actually titlecase the text?\n\nWhenever you run any operator in Vim, there are three different action motion types: character, line, and block. `g@w` (word) is an example of a character operation. `g@j` (one line below) is an example of a line operation. Block operation is rare, but typically when you do `Ctrl-V` (visual block) operation, it will be counted as a block operation. Operations that target a few characters forward / backward are generally considered character operations (`b`, `e`, `w`, `ge`, etc). Operations that target a few lines downward / upward are generally considered line operations (`j`, `k`). Operations that target columns forward, backward, upward, or downward are generally considered block operations (they are usually either a columnar forced-motion or a blockwise visual mode; for more: `:h forced-motion`).\n\nThis means, if you press `g@w`, `g@` will pass a literal string `\"char\"` as an argument to `ToTitle()`. If you do `g@j`, `g@` will pass a literal string `\"line\"` as an argument to `ToTitle()`. This string is what will be passed into the `ToTitle` function as the `type` argument.\n\n## Creating Your Own Custom Function Operator\n\nLet's pause and play with `g@` by writing a dummy function:\n\n```\nfunction! Test(some_arg)\n  echom a:some_arg \nendfunction\n```\n\nNow assign that function to `opfunc` by running:\n\n```\n:set opfunc=Test\n```\n\nThe `g@` operator will execute `Test(some_arg)` and passes it with either `\"char\"`, `\"line\"`, or `\"block\"` depending on what operation you do. Run different operations like `g@iw` (inner word), `g@j` (one line below), `g@$` (to the end of the line), etc. See what different values are being echoed. To test the block operation, you can use Vim's forced motion for block operations: `g@Ctrl-Vj` (block operation one column below).\n\nYou can also use it with the visual mode. Use the various visual highlights like `v`, `V`, and `Ctrl-V` then press `g@` (be warned, it will flash the output echo really quickly, so you need to have a quick eye - but the echo is definitely there. Also, since you are using `echom`, you can check the recorded echo messages with `:messages`).\n\nPretty cool, isn't it? The things you can program with Vim! Why didn't they teach this at school? Let's continue with our plugin.\n\n## ToTitle As a Function\n\nMoving on to the next few lines:\n\n```\nif a:type != 'block' && a:type != 'line' && a:type != 'char'\n  let l:words = a:type\n  let l:wordsArr = trim(l:words)->split('\\s\\+')\n  call map(l:wordsArr, 's:capitalize(v:val)')\n  return l:wordsArr->join(' ')\nendif\n```\n\nThis line actually has nothing to do with `ToTitle()` behavior an operator, but to enable it into a callable TitleCase function (yes, I know that I am violating the Single Responsibility Principle). The motivation is, Vim has native `toupper()` and `tolower()` functions that will uppercase and lowercase any given string. Ex: `:echo toupper('hello')` returns `'HELLO'` and `:echo tolower('HELLO')` returns `'hello'`. I want this plugin to have the ability to run `ToTitle` so you can do `:echo ToTitle('once upon a time')` and get a `'Once Upon a Time'` return value.\n\nBy now, you know that when you are calling `ToTitle(type)` with `g@`, the `type` argument will have a value of either `'block'`, `'line'`, or `'char`'. If the argument is neither `'block'` nor `'line'` nor `'char'`, you can safely assume that `ToTitle()` is being called outside of `g@`. In that case, you split them by whitespaces (`\\s\\+`) with:\n\n```\nlet l:wordsArr = trim(l:words)->split('\\s\\+')\n```\n\nThen capitalize each element:\n\n\n```\ncall map(l:wordsArr, 's:capitalize(v:val)')\n```\n\nBefore joining them back together:\n\n```\nl:wordsArr->join(' ')\n```\n\n\nThe `capitalize()` function will be covered later.\n\n## Temporary Variables\n\nThe next few lines:\n\n```\nlet l:sel_save = &selection\nlet l:reg_save = getreginfo('\"')\nlet l:cb_save = &clipboard\nlet l:visual_marks_save = [getpos(\"'<\"), getpos(\"'>\")]\n```\n\nThese lines preserve various current states into temporary variables. Later in this you will use visual modes, marks, and registers. Doing these will tamper with a few states. Since you don't want to revise the history, you need to save them into temporary variables so you can restore the states later.\n\n## Capitalizing the Selections\n\nThe next lines are important:\n\n```\ntry\n  set clipboard= selection=inclusive\n  let l:commands = #{line: \"'[V']y\", char: \"`[v`]y\", block: \"`[\\<c-v>`]y\"}\n\n  silent exe 'noautocmd keepjumps normal! ' .. get(l:commands, a:type, '')\n  let l:selected_phrase = getreg('\"')\n  let l:WORD_PATTERN = '\\<\\k*\\>'\n  let l:UPCASE_REPLACEMENT = '\\=s:capitalize(submatch(0))'\n\n  let l:startLine = line(\"'<\")\n  let l:startCol = virtcol(\".\")\n\n```\nLet's go through them in small chunks. This line:\n\n```\nset clipboard= selection=inclusive\n```\n\nYou first set the `selection` option to be inclusive and the `clipboard` to be empty. The selection attribute is typically used with the visual mode and there are three possible values: `old`, `inclusive`, and `exclusive`. Setting it to be inclusive means that the last character of the selection is included. I won't cover them here, but the point is that choosing it to be inclusive makes it behave consistently in visual mode. By default Vim sets it to inclusive, but you set it here anyway just in case one of your plugins sets it to a different value. Check out `:h 'clipboard'` and `:h 'selection'` if you're curious what they really do.\n\nNext you have this weird-looking hash followed by an execute command:\n\n```\nlet l:commands = #{line: \"'[V']y\", char: \"`[v`]y\", block: \"`[\\<c-v>`]y\"}\nsilent exe 'noautocmd keepjumps normal! ' .. get(l:commands, a:type, '')\n```\n\nFirst, the `#{}` syntax is Vim's dictionary data type. The local variable `l:commands` is a hash with 'lines', 'char', and 'block' as its keys. The command `silent exe '...'` executes whatever command inside the string silently (otherwise it will display notifications to the bottom of your screen). \n\nSecond, the executed commands are `'noautocmd keepjumps normal! ' .. get(l:commands, a:type, '')`. The first one, `noautocmd`, will execute the subsequent command without triggering any autocommand. The second one, `keepjumps`, is to not record the cursor movement while moving. In Vim, certain motions are automatically recorded in the change list, the jump list, and the mark list. This prevents that. The point of having `noautocmd` and `keepjumps` is to prevent side effects. Finally, the `normal` command executes the strings as normal commands. The `..` is Vim's string interpolation syntax. `get()` is a getter method that accepts either a list, blob, or dictionary. In this case, you are passing it the dictionary `l:commands`. The key is `a:type`. You learned earlier that `a:type` is either one of the three string values: 'char', 'line', or 'block'. So if `a:type` is 'line', you will be executing `\"noautocmd keepjumps normal! '[V']y\"` (for more, check out `:h silent`, `:h :exe`, `:h :noautocmd`, `:h :keepjumps`, `:h :normal`, and `:h get()`).\n\nLet's go over what `'[V']y` does. First assume that you have this body of text:\n\n```\nthe second breakfast\nis better than the first breakfast\n```\nAssume that your cursor is on the first line. Then you press `g@j` (run the operator function, `g@`, one line below, with `j`). `'[` moves the cursor to the start of the previously changed or yanked text. Although you technically didn't change or yank any text with `g@j`, Vim remembers the locations of the start and the end motions of the `g@` command with `'[` and `']` (for more, check out `:h g@`). In your case, pressing `'[` moves your cursor to the first line because that's where you started when you ran `g@`. `V` is a linewise visual mode command. Finally, `']` moves your cursor to the end of the previous changed or yanked text, but in this case, it moves your cursor to the end of your last `g@` operation. Finally, `y` yanks the selected text. \n\nWhat you just did was yanking the same body of text you performed `g@` on.\n\nIf you look at the other two commands in here:\n\n```\nlet l:commands = #{line: \"'[V']y\", char: \"`[v`]y\", block: \"`[\\<c-v>`]y\"}\n```\n\nThey all perform similar actions, except instead of using linewise actions, you would be using characterwise or blockwise actions. I'm going to sound redundant, but in any three cases you are effectively yanking the same body of text you performed `g@` on.\n\nLet's look at the next line:\n\n```\nlet l:selected_phrase = getreg('\"')\n```\n\nThis line gets the content of the unnamed register (`\"`) and stores it inside the variable `l:selected_phrase`.  Wait a minute... didn't you just yank a body of text? The unnamed register currently contains the text that you had just yanked. This is how this plugin is able to get the copy of the text.\n\nThe next line is a regular expression pattern:\n\n```\nlet l:WORD_PATTERN = '\\<\\k*\\>'\n```\n\n`\\<` and `\\>` are word boundary patterns. The character following `\\<` matches the beginning of a word and the character preceding `\\>` matches the end of a word. `\\k` is the keyword pattern. You can check what characters Vim accepts as keywords with `:set iskeyword?`. Recall that the `w` motion in Vim moves your cursor word-wise. Vim comes with a pre-conceied notion of what a \"keyword\" is (you can even edit them by altering the `iskeyword` option). Check out `:h /\\<`, `:h /\\>`, and `:h /\\k`, and `:h 'iskeyword'` for more. Finally, `*` means zero or more of the subsequent pattern.\n\nIn the big picture, `'\\<\\k*\\>'` matches a word. If you have a string:\n\n```\none two three\n```\n\nMatching it against the pattern will give you three matches: \"one\", \"two\", and \"three\".\n\nFinally, you have another pattern:\n\n```\nlet l:UPCASE_REPLACEMENT = '\\=s:capitalize(submatch(0))'\n```\n\nRecall that Vim's substitute command can be used with an expression with `\\={your-expression}`. For example, if you want to uppercase the string \"donut\" in the current line, you can use Vim's `toupper()` function. You can achieve this by running `:%s/donut/\\=toupper(submatch(0))/g`. `submatch(0)` is a special expression used in the substitute command. It returns the whole matched text.\n\nThe next two lines:\n\n```\nlet l:startLine = line(\"'<\")\nlet l:startCol = virtcol(\".\")\n```\n\nThe `line()` expression returns a line number. Here you pass it with the mark `'<`, representing the first line of the last selected visual area. Recall that you used visual mode to yank the text. `'<` returns the line number of the beginning of that visual area selection. The `virtcol()` expression returns a column number of the current cursor. You will be moving your cursor all over the place in a little bit, so you need to store your cursor location so you can return here later.\n\nTake a break here and review everything so far. Make sure you are still following along. When you're ready, let's continue.\n\n## Handling a Block Operation\n\nLet's go through this section:\n\n```\nif a:type ==# \"block\"\n  sil! keepj norm! gv\"ad\n  keepj $\n  keepj pu_\n\n  let l:lastLine = line(\"$\")\n\n  sil! keepj norm \"ap\n\n  let l:curLine = line(\".\")\n\n  sil! keepj norm! VGg@\n  exe \"keepj norm! 0\\<c-v>G$h\\\"ad\" \n  exe \"keepj \" . l:startLine\n  exe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\\\"aP\"\n  exe \"keepj \" . l:lastLine\n  sil! keepj norm! \"_dG\n  exe \"keepj \" . l:startLine\n  exe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\"\n```\n\nIt's time to actually capitalize your text. Recall that you have the `a:type` to be either 'char', 'line', or 'block'. In most cases, you'll probably be getting 'char' and 'line'. But occasionally you may get a block. It is rare, but it must be addressed nonetheless. Unfortunately, handling a block is not as straight-forward as handling char and line. It will take a little extra effort, but it is doable.\n\nBefore you start, let's take an example of how you might get a block. Assume that you have this text:\n\n```\npancake for breakfast\npancake for lunch\npancake for dinner\n```\n\nAssume that your cursor is on \"c\" on \"pancake\" on the first line. You then use the visual block (`Ctrl-V`) to select down and forward to select the \"cake\" in all three lines:\n\n```\npan[cake] for breakfast\npan[cake] for lunch\npan[cake] for dinner\n```\n\nWhen you press `gt`, you want to get:\n\n```\npanCake for breakfast\npanCake for lunch\npanCake for dinner\n\n```\nHere are your basic assumptions: when you highlight the three \"cakes\" in \"pancakes\", you are telling Vim that you have three lines of words that you want to highlight. These words are \"cake\", \"cake\", and \"cake\". You expect to get \"Cake\", \"Cake\", and \"Cake\".\n\nLet's move on to the implementation details. The next few lines have:\n\n```\nsil! keepj norm! gv\"ad\nkeepj $\nkeepj pu_\nlet l:lastLine = line(\"$\")\nsil! keepj norm \"ap\nlet l:curLine = line(\".\")\n```\n\nThe first line:\n\n```\nsil! keepj norm! gv\"ad\n```\n\nRecall that `sil!` runs silently and `keepj` keeps the jump history when moving. You then execute the normal command `gv\"ad`. `gv` selects the last visually highlighted text (in the pancakes example, it will re-highlight all three 'cakes'). `\"ad` deletes the visually highlighted texts and stores them in register a. As a result, you now have:\n\n```\npan for breakfast\npan for lunch\npan for dinner\n```\n\nNow you have 3 *blocks* (not lines) of 'cakes' stored in the register a. This distinction is important. Yanking a text with linewise visual mode is different from yanking a text with blockwise visual mode. Keep this in mind because you will see this again later.\n\nNext you have:\n\n```\nkeepj $\nkeepj pu_\n```\n\n`$` moves you to the last line in your file. `pu_` inserts one line below where your cursor is. You want to run them with `keepj` so you don't alter the jump history.\n\nThen you store the line number of your last line (`line(\"$\")`) in the local variable `lastLine`.\n\n```\nlet l:lastLine = line(\"$\")\n```\n\nThen paste the content from the register with `norm \"ap`.\n\n```\nsil! keepj norm \"ap\n```\n\nKeep in mind that this is happening on the new line you created below the last line of the file - you are currently at the bottom of the file. Pasting give you these *block* texts:\n\n```\ncake\ncake\ncake\n```\n\nNext, you store the location of the current line where your cursor is.\n\n```\nlet l:curLine = line(\".\")\n```\n\nNow let's go the next few lines:\n\n```\nsil! keepj norm! VGg@\nexe \"keepj norm! 0\\<c-v>G$h\\\"ad\"\nexe \"keepj \" . l:startLine\nexe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\\\"aP\"\nexe \"keepj \" . l:lastLine\nsil! keepj norm! \"_dG\nexe \"keepj \" . l:startLine\nexe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\"\n```\n\nThis line:\n\n```\nsil! keepj norm! VGg@\n```\n\n`VG` visually highlights them with line visual mode from the current line to the end of the file. So here you are highlighting the three blocks of 'cake' texts with linewise highlight (recall the block vs line distinction). Note that the first time you pasted the three \"cake\" texts, you were pasting them as blocks. Now you are highlighting them as lines. They may look the same from the outside, but internally, Vim knows the difference between pasting blocks of texts and pasting lines of texts.\n\n```\ncake\ncake\ncake\n```\n\n`g@` is the function operator, so you are essentially doing a recursive call to itself. But why? What does this accomplish?\n\nYou are making a recursive call to `g@` and passing it with all 3 lines (after running it with `V`, you now have lines, not blocks) of 'cake' texts so it will be handled by the other part of the code (you will go over this later). The result of running `g@` is three lines of properly titlecased texts:\n\n```\nCake\nCake\nCake\n```\n\nThe next line:\n\n```\nexe \"keepj norm! 0\\<c-v>G$h\\\"ad\"\n```\n\nThis runs the normal mode command to go to the beginning of the line (`0`), use the block visual highlight to go to the last line and last character on that line (`<c-v>G$`). The `h` is to adjust the cursor (when doing `$` Vim moves one extra line to the right). Finally, you delete the highlighted text and store it in the register a (`\"ad`).\n\nThe next line:\n\n```\nexe \"keepj \" . l:startLine\n```\n\nYou move your cursor back to where the `startLine` was.\n\nNext:\n\n```\nexe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\\\"aP\"\n```\n\nBeing in the `startLine` location, you now jump to the column marked by `startCol`. `\\<bar>\\` is the bar `|` motion. The bar motion in Vim moves your cursor to the nth column (let's say the `startCol` was 4. Running `4|` will make your cursor jump to the column position of 4). Recall that you `startCol` was the location where you stored the column position of the text you wanted to titlecase. Finally, `\"aP` pastes the texts stored in the register a. This puts the text back to where it was deleted before.\n\nLet's look at the next 4 lines:\n\n```\nexe \"keepj \" . l:lastLine\nsil! keepj norm! \"_dG\nexe \"keepj \" . l:startLine\nexe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\"\n```\n\n`exe \"keepj \" . l:lastLine` moves your cursor back to the `lastLine` location from earlier. `sil! keepj norm! \"_dG` deletes the extra space(s) that were created using the blackhole register (`\"_dG`) so your unnamed register stays clean. `exe \"keepj \" . l:startLine` moves your cursor back to `startLine`. Finally, `exe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\"` moves your cursor to the `startCol` column.\n\nThese are all the actions you could've done manually in Vim. However, the benefit of turning these actions into reusable functions is that they will save you from running 30+ lines of instructions every single time you need to titlecase anything. The take home here is, anything that you can do manually in Vim, you can turn it into a reusable function, hence a plugin!\n\nHere is what it would look like.\n\nGiven some text:\n\n```\npancake for breakfast\npancake for lunch\npancake for dinner\n\n... some text\n```\n\nFirst, you visually highlight it blockwise:\n\n```\npan[cake] for breakfast\npan[cake] for lunch\npan[cake] for dinner\n\n... some text\n```\n\nThen you delete it and store that text in register a:\n\n```\npan for breakfast\npan for lunch\npan for dinner\n\n... some text\n```\n\nThen you paste it at the bottom of the file:\n\n```\npan for breakfast\npan for lunch\npan for dinner\n\n... some text\ncake\ncake\ncake\n```\n\nThen you capitalize it:\n\n```\npan for breakfast\npan for lunch\npan for dinner\n\n... some text\nCake\nCake\nCake\n```\n\nFinally, you put the capitalized text back:\n\n```\npanCake for breakfast\npanCake for lunch\npanCake for dinner\n\n... some text\n```\n\n## Handling Line and Char Operations\n\nYou are not done yet. You've only addressed the edge case when you run `gt` on block texts. You still need to handle the 'line' and 'char' operations. Let's look at the `else` code to see how this is done.\n\nHere are the codes:\n\n```\nif a:type ==# \"block\"\n  # ... \nelse\n  let l:titlecased = substitute(@@, l:WORD_PATTERN, l:UPCASE_REPLACEMENT, 'g')\n  let l:titlecased = s:capitalizeFirstWord(l:titlecased)\n  call setreg('\"', l:titlecased)\n  let l:subcommands = #{line: \"'[V']p\", char: \"`[v`]p\", block: \"`[\\<c-v>`]p\"}\n  silent execute \"noautocmd keepjumps normal! \" .. get(l:subcommands, a:type, \"\")\n  exe \"keepj \" . l:startLine\n  exe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\"\nendif\n```\n\nLet's go through them linewise. The secret sauce of this plugin is actually on this line:\n\n```\nlet l:titlecased = substitute(@@, l:WORD_PATTERN, l:UPCASE_REPLACEMENT, 'g')\n```\n\n`@@` contains the text from the unnamed register to be titlecased. `l:WORD_PATTERN` is the individual keyword match. `l:UPCASE_REPLACEMENT` is the call to the `capitalize()` command (which you will see later). The `'g'` is the global flag that instructs the substitute command to substitute all given words, not just the first word.\n\nThe next line:\n\n```\nlet l:titlecased = s:capitalizeFirstWord(l:titlecased)\n```\n\nThis guarantees that the first word will always be capitalized. If you have a phrase like \"an apple a day keeps the doctor away\", since the first word, \"an\", is a special word, your substitute command won't capitalize it. You need a a method that always capitalizes the first character no matter what. This function does just that (you will see this function detail later). The result of these capitalization methods is stored in the local variable `l:titlecased`.\n\nThe next line:\n\n```\ncall setreg('\"', l:titlecased)\n```\n\nThis puts the capitalized string into the unnamed register (`\"`).\n\nNext, the following two lines:\n\n```\nlet l:subcommands = #{line: \"'[V']p\", char: \"`[v`]p\", block: \"`[\\<c-v>`]p\"}\nsilent execute \"noautocmd keepjumps normal! \" .. get(l:subcommands, a:type, \"\")\n```\n\nHey, that looks familiar! You have seen a similar pattern before with `l:commands`. Instead of yank, here you use paste (`p`). Check out the previous section where I went over the `l:commands` for a refresher.\n\nFinally, these two lines:\n\n```\nexe \"keepj \" . l:startLine\nexe \"sil! keepj norm! \" . l:startCol . \"\\<bar>\"\n```\n\nYou are moving your cursor back to the line and column where you started. That's it!\n\nLet's recap. The above substitute method is smart enough to capitalize the given texts and skip the special words (more on this later). After you have a titlecased string, you store them in the unnamed register. Then you visually highlight the exact same text you operated `g@` on before, then paste from the unnamed register (this effectively replaces the non-titlecased texts with the titlecased version. Finally, you move your cursor back to where you started.\n\n## Cleanups\n\nYou are technically done. The texts are now titlecased. All that is left to do is to restore the registers and settings.\n\n```\ncall setreg('\"', l:reg_save)\ncall setpos(\"'<\", l:visual_marks_save[0])\ncall setpos(\"'>\", l:visual_marks_save[1])\nlet &clipboard = l:cb_save\nlet &selection = l:sel_save\n```\n\nThese restore:\n- the unnamed register.\n- the `<` and `>` marks.\n- the `'clipboard'` and `'selection'` options.\n\nPhew, you are done. That was a long function. I could have made the function shorter by breaking it apart into smaller ones, but for now, that will have to suffice. Now let's briefly go over the capitalize functions.\n\n## The Capitalize Function\n\nIn this section, let's go over the `s:capitalize()` function. This is what the function looks like:\n\n```\nfunction! s:capitalize(string)\n    if(toupper(a:string) ==# a:string && a:string != 'A')\n        return a:string\n    endif\n\n    let l:str = tolower(a:string)\n    let l:exclusions = '^\\(a\\|an\\|and\\|at\\|but\\|by\\|en\\|for\\|in\\|nor\\|of\\|off\\|on\\|or\\|out\\|per\\|so\\|the\\|to\\|up\\|yet\\|v\\.?\\|vs\\.?\\|via\\)$'\n    if (match(l:str, l:exclusions) >= 0) || (index(s:local_exclusion_list, l:str) >= 0)\n      return l:str\n    endif\n\n    return toupper(l:str[0]) . l:str[1:]\nendfunction\n```\n\nRecall that the argument for the `capitalize()` function, `a:string`, is the individual word passed by the `g@` operator. So if I am running `gt` on the text \"pancake for breakfast\", `ToTitle`  will call `capitalize(string)` *three* times, once for \"pancake\", once for \"for\", and once for \"breakfast\".\n\nThe first part of the function is:\n\n```\nif(toupper(a:string) ==# a:string && a:string != 'A')\n  return a:string\nendif\n```\n\nThe first condition (`toupper(a:string) ==# a:string`) checks whether the uppercased version of the argument is the same as the string and whether the string itself is \"A\". If these are true, then return that string. This is based on the assumption that if a given word is already totally uppercased, then it is an abbreviation. For example, the word \"CEO\" would otherwise be converted into \"Ceo\". Hmm, your CEO won't be happy. So it's best to leave any fully uppercased word alone. The second condition, `a:string != 'A'`, addresses an edge case for a capitalized \"A\" character. If `a:string` is already a capitalized \"A\", it would have accidentally passed the `toupper(a:string) ==# a:string` test. Because \"a\" is an indefinite article in English, it needs to be lowercased.\n\nThe next part forces the string to be lowercased:\n\n```\nlet l:str = tolower(a:string)\n```\n\n\nThe next part is a regex of a list of all word exclusions. I got them from https://titlecaseconverter.com/rules/ :\n\n```\nlet l:exclusions = '^\\(a\\|an\\|and\\|at\\|but\\|by\\|en\\|for\\|in\\|nor\\|of\\|off\\|on\\|or\\|out\\|per\\|so\\|the\\|to\\|up\\|yet\\|v\\.?\\|vs\\.?\\|via\\)$'\n```\n\nThe next part:\n\n```\nif (match(l:str, l:exclusions) >= 0) || (index(s:local_exclusion_list, l:str) >= 0)\n  return l:str\nendif\n```\n\nFirst, check if your string is a part of the excluded word list (`l:exclusions`). If it is, don't capitalize it. Then check if your string is a part of the local exclusion list (`s:local_exclusion_list`). This exclusion list is a custom list that the user can add in vimrc (in case the user has additional requirements for special words).\n\nThe last part returns the capitalized version of the word. The first character is uppercased while the rest remains as is.\n\n```\nreturn toupper(l:str[0]) . l:str[1:]\n```\n\nLet's go over the second capitalize function. The function looks like this:\n\n```\nfunction! s:capitalizeFirstWord(string)\n  if (a:string =~ \"\\n\")\n    let l:lineArr = trim(a:string)->split('\\n')\n    let l:lineArr = map(l:lineArr, 'toupper(v:val[0]) . v:val[1:]')\n    return l:lineArr->join(\"\\n\")\n  endif\n  return toupper(a:string[0]) . a:string[1:]\nendfunction\n```\n\nThis function was created to handle an edge case if you have a sentence that starts with an excluded word, like \"an apple a day keeps the doctor away\". Based on English language's capitalization rules, all first words in a sentence, regardless if it is a special word or not, must be capitalized. With your `substitute()` command alone, the \"an\" in your sentence would be lowercased. You need to force the first character to be uppercased.\n\nIn this `capitalizeFirstWord` function, the `a:string` argument is not an individual word like `a:string` inside the `capitalize` function, but instead the whole text. So if you have \"pancake for breakfast\", `a:string`'s value is \"pancake for breakfast\". It only runs `capitalizeFirstWord` once for the whole text. \n\nOne scenario you need to watch out for is if you have a multi-line string like `\"an apple a day\\nkeeps the doctor away\"`. You want to uppercase the first character of all lines. If you don't have newlines, then simply uppercase the first character.\n\n```\nreturn toupper(a:string[0]) . a:string[1:]\n```\n\nIf you have newlines, you need to capitalize all the first characters in each line, so you split them into an array separated by newlines:\n\n```\nlet l:lineArr = trim(a:string)->split('\\n')\n```\n\nThen you map each element in the array and capitalize the first word of each element:\n\n```\nlet l:lineArr = map(l:lineArr, 'toupper(v:val[0]) . v:val[1:]')\n```\n\nFinally, you put the array elements together:\n\n```\nreturn l:lineArr->join(\"\\n\")\n```\n\nAnd you are done!\n\n## Docs\n\nThe second directory in the repository is the `docs/` directory. It is good to provide the plugin with a thorough documentation. In this section, I'll briefly go over how to make your own plugin docs.\n\nThe `docs/` directory is one of Vim's special runtime paths. Vim reads all the files inside the `docs/` so when you search for a special keyword and that keyword is found in one of the files in the `docs/` directory, it will display it in the help page. Here you have a `totitle.txt`. I name it that way because that's the plugin name, but you can name it anything you want.\n\nA Vim docs file is a txt file at heart. The difference between a regular txt file and a Vim help file is that the latter uses special \"help\" syntaxes. But first, you need to tell Vim to treat it not as a text file type, but as a `help` file type. To tell Vim to interpret this `totitle.txt` as a *help* file, run `:set ft=help` (`:h 'filetype'` for more). By the way, if you want to tell Vim to interpret this `totitle.txt` as a *regular* txt file, run `:set ft=txt`.\n\n### The Help File Special Syntax\n\nTo make a keyword discoverable, surround that keyword with asterisks. To make the keyword `totitle` discoverable when user searches for `:h totitle`, write it as `*totitle*` in the help file.\n\nFor example, I have these lines on top of my table of contents:\n\n```\nTABLE OF CONTENTS                                     *totitle*  *totitle-toc*\n\n// more TOC stuff\n```\n\nNote that I used two keywords: `*totitle*` and `*totitle-toc*` to mark the table of contents section. You can use as many keywords as you want. This means that whenever you search for either `:h totitle` or `:h totitle-toc`, Vim takes you to this location. \n\nHere is another example, somewhere down the file:\n\n```\n2. Usage                                                       *totitle-usage*\n\n// usage\n```\n\nIf you search for `:h totitle-usage`, Vim takes you to this section. \n\nYou can also use internal links to refer to another section in the help file by surrounding a keyword with the bar syntax `|`. In the TOC section, you see keywords surrounded by the bars, like `|totitle-intro|`, `|totitle-usage|`, etc.\n\n```\nTABLE OF CONTENTS                                     *totitle*  *totitle-toc*\n\n    1. Intro ........................... |totitle-intro|\n    2. Usage ........................... |totitle-usage|\n    3. Words to capitalize ............. |totitle-words|\n    4. Operator ........................ |totitle-operator|\n    5. Key-binding ..................... |totitle-keybinding|\n    6. Bugs ............................ |totitle-bug-report|\n    7. Contributing .................... |totitle-contributing|\n    8. Credits ......................... |totitle-credits|\n\n```\nThis lets you jump to the definition. If you put your cursor somewhere on `|totitle-intro|` and press `Ctrl-]`, Vim will jump to the definition of that word. In this case, it will jump to the `*totitle-intro*` location. This is how you can link to different keywords in a help doc.\n\nThere is not a right or wrong way to write a doc file in Vim. If you look at different plugins by different authors, many of them use different formats. The point is to make an easy-to-understand help doc for your users.\n\nFinally, if you are writing your own plugin locally at first and you want to test the documentation page, simply adding a txt file inside the `~/.vim/docs/` won't automatically make your keywords searchable. You need to instruct Vim to add your doc page. Run the helptags command: `:helptags ~/.vim/doc` to create new tag files. Now you can start searching for your keywords.\n\n## Conclusion\n\nYou made it to the end! This chapter is the amalgamation of all the Vimscript chapters. Here you are finally putting to practice what you've learned so far. Hopefully having read this, you understood not only how to create Vim plugins, but also encouraged you to write your own plugin. \n\nWhenever you find yourself repeating the same sequence of actions multiple times, you should try to create your own! It was said that you shouldn't reinvent the wheel. However, I think it can be beneficial to reinvent the wheel for the sake of learning. Read other people's plugins. Recreate them. Learn from them. Write your own! Who knows, maybe you will write the next awesome, super-popular plugin after reading this. Maybe you will be the next legendary Tim Pope. When that happens, let me know! \n\n## Link\n- Prev [Ch28. Vimscript Functions](./ch28_vimscript_functions.md)\n"
  }
]