Full Code of micro-editor/micro for AI

master 6760768b9ec6 cached
328 files
1.2 MB
375.3k tokens
1331 symbols
1 requests
Download .txt
Showing preview only (1,283K chars total). Download the full file or copy to clipboard to get everything.
Repository: micro-editor/micro
Branch: master
Commit: 6760768b9ec6
Files: 328
Total size: 1.2 MB

Directory structure:
gitextract_jznqtz0z/

├── .editorconfig
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 01-bug.yml
│   │   ├── 02-feature.yml
│   │   └── config.yml
│   └── workflows/
│       ├── nightly.yaml
│       ├── release.yaml
│       └── test.yaml
├── .gitignore
├── LICENSE
├── LICENSE-THIRD-PARTY
├── Makefile
├── README.md
├── assets/
│   └── packaging/
│       ├── deb/
│       │   ├── micro.postinst
│       │   └── micro.prerm
│       ├── micro.1
│       └── micro.desktop
├── cmd/
│   └── micro/
│       ├── clean.go
│       ├── debug.go
│       ├── initlua.go
│       ├── micro.go
│       └── micro_test.go
├── data/
│   ├── io.github.zyedidia.micro.metainfo.xml
│   └── micro.json
├── go.mod
├── go.sum
├── internal/
│   ├── action/
│   │   ├── actions.go
│   │   ├── actions_other.go
│   │   ├── actions_posix.go
│   │   ├── bindings.go
│   │   ├── bufpane.go
│   │   ├── command.go
│   │   ├── defaults.go
│   │   ├── defaults_darwin.go
│   │   ├── defaults_other.go
│   │   ├── events.go
│   │   ├── globals.go
│   │   ├── infocomplete.go
│   │   ├── infopane.go
│   │   ├── keytree.go
│   │   ├── pane.go
│   │   ├── rawpane.go
│   │   ├── tab.go
│   │   ├── terminal_supported.go
│   │   ├── terminal_unsupported.go
│   │   └── termpane.go
│   ├── buffer/
│   │   ├── autocomplete.go
│   │   ├── backup.go
│   │   ├── buffer.go
│   │   ├── buffer_generated_test.go
│   │   ├── buffer_test.go
│   │   ├── cursor.go
│   │   ├── eventhandler.go
│   │   ├── line_array.go
│   │   ├── line_array_test.go
│   │   ├── loc.go
│   │   ├── message.go
│   │   ├── save.go
│   │   ├── search.go
│   │   ├── serialize.go
│   │   ├── settings.go
│   │   ├── stack.go
│   │   └── stack_test.go
│   ├── clipboard/
│   │   ├── clipboard.go
│   │   ├── internal.go
│   │   ├── multi.go
│   │   └── terminal.go
│   ├── config/
│   │   ├── autosave.go
│   │   ├── colorscheme.go
│   │   ├── colorscheme_test.go
│   │   ├── config.go
│   │   ├── globals.go
│   │   ├── plugin.go
│   │   ├── plugin_installer.go
│   │   ├── plugin_installer_test.go
│   │   ├── plugin_manager.go
│   │   ├── rtfiles.go
│   │   ├── rtfiles_test.go
│   │   └── settings.go
│   ├── display/
│   │   ├── bufwindow.go
│   │   ├── infowindow.go
│   │   ├── softwrap.go
│   │   ├── statusline.go
│   │   ├── tabwindow.go
│   │   ├── termwindow.go
│   │   ├── uiwindow.go
│   │   └── window.go
│   ├── info/
│   │   ├── gutter.go
│   │   ├── history.go
│   │   └── infobuffer.go
│   ├── lua/
│   │   └── lua.go
│   ├── screen/
│   │   ├── message.go
│   │   └── screen.go
│   ├── shell/
│   │   ├── job.go
│   │   ├── shell.go
│   │   └── terminal.go
│   ├── util/
│   │   ├── lua.go
│   │   ├── profile.go
│   │   ├── unicode.go
│   │   ├── util.go
│   │   └── util_test.go
│   └── views/
│       ├── splits.go
│       └── splits_test.go
├── pkg/
│   └── highlight/
│       ├── highlighter.go
│       ├── parser.go
│       └── unicode.go
├── runtime/
│   ├── README.md
│   ├── colorschemes/
│   │   ├── atom-dark.micro
│   │   ├── bubblegum.micro
│   │   ├── cmc-16.micro
│   │   ├── cmc-tc.micro
│   │   ├── darcula.micro
│   │   ├── default.micro
│   │   ├── dracula-tc.micro
│   │   ├── dukedark-tc.micro
│   │   ├── dukelight-tc.micro
│   │   ├── dukeubuntu-tc.micro
│   │   ├── geany.micro
│   │   ├── gotham.micro
│   │   ├── gruvbox-tc.micro
│   │   ├── gruvbox.micro
│   │   ├── material-tc.micro
│   │   ├── monokai-dark.micro
│   │   ├── monokai.micro
│   │   ├── one-dark.micro
│   │   ├── railscast.micro
│   │   ├── simple.micro
│   │   ├── solarized-tc.micro
│   │   ├── solarized.micro
│   │   ├── sunny-day.micro
│   │   ├── twilight.micro
│   │   └── zenburn.micro
│   ├── help/
│   │   ├── colors.md
│   │   ├── commands.md
│   │   ├── copypaste.md
│   │   ├── defaultkeys.md
│   │   ├── help.md
│   │   ├── keybindings.md
│   │   ├── options.md
│   │   ├── plugins.md
│   │   └── tutorial.md
│   ├── plugins/
│   │   ├── autoclose/
│   │   │   └── autoclose.lua
│   │   ├── comment/
│   │   │   ├── comment.lua
│   │   │   └── help/
│   │   │       └── comment.md
│   │   ├── diff/
│   │   │   └── diff.lua
│   │   ├── ftoptions/
│   │   │   └── ftoptions.lua
│   │   ├── linter/
│   │   │   ├── help/
│   │   │   │   └── linter.md
│   │   │   └── linter.lua
│   │   ├── literate/
│   │   │   ├── README.md
│   │   │   └── literate.lua
│   │   └── status/
│   │       ├── help/
│   │       │   └── status.md
│   │       └── status.lua
│   ├── runtime.go
│   ├── runtime_test.go
│   └── syntax/
│       ├── LICENSE
│       ├── PowerShell.yaml
│       ├── README.md
│       ├── ada.yaml
│       ├── apacheconf.yaml
│       ├── arduino.yaml
│       ├── asciidoc.yaml
│       ├── asm.yaml
│       ├── ats.yaml
│       ├── awk.yaml
│       ├── b.yaml
│       ├── bat.yaml
│       ├── c.yaml
│       ├── caddyfile.yaml
│       ├── cake.yaml
│       ├── clojure.yaml
│       ├── cmake.yaml
│       ├── coffeescript.yaml
│       ├── colortest.yaml
│       ├── conky.yaml
│       ├── cpp.yaml
│       ├── crontab.yaml
│       ├── crystal.yaml
│       ├── csharp.yaml
│       ├── css.yaml
│       ├── csx.yaml
│       ├── cuda.yaml
│       ├── cython.yaml
│       ├── d.yaml
│       ├── dart.yaml
│       ├── default.yaml
│       ├── dockerfile.yaml
│       ├── dot.yaml
│       ├── elixir.yaml
│       ├── elm.yaml
│       ├── erb.yaml
│       ├── erlang.yaml
│       ├── fish.yaml
│       ├── forth.yaml
│       ├── fortran.yaml
│       ├── freebsd-kernel.yaml
│       ├── fsharp.yaml
│       ├── gdscript.yaml
│       ├── gemini.yaml
│       ├── gentoo-ebuild.yaml
│       ├── gentoo-etc-portage.yaml
│       ├── git-commit.yaml
│       ├── git-config.yaml
│       ├── git-rebase-todo.yaml
│       ├── glsl.yaml
│       ├── gnuplot.yaml
│       ├── go.yaml
│       ├── godoc.yaml
│       ├── golo.yaml
│       ├── gomod.yaml
│       ├── graphql.yaml
│       ├── groff.yaml
│       ├── groovy.yaml
│       ├── haml.yaml
│       ├── hare.yaml
│       ├── haskell.yaml
│       ├── hc.yaml
│       ├── html.yaml
│       ├── html4.yaml
│       ├── html5.yaml
│       ├── ini.yaml
│       ├── inputrc.yaml
│       ├── java.yaml
│       ├── javascript.yaml
│       ├── jinja2.yaml
│       ├── json.yaml
│       ├── jsonnet.yaml
│       ├── julia.yaml
│       ├── justfile.yaml
│       ├── keymap.yaml
│       ├── kickstart.yaml
│       ├── kotlin.yaml
│       ├── kvlang.yaml
│       ├── ledger.yaml
│       ├── lfe.yaml
│       ├── lilypond.yaml
│       ├── lisp.yaml
│       ├── log.yaml
│       ├── lua.yaml
│       ├── mail.yaml
│       ├── make_headers.go
│       ├── makefile.yaml
│       ├── man.yaml
│       ├── markdown.yaml
│       ├── mc.yaml
│       ├── meson.yaml
│       ├── micro.yaml
│       ├── mpdconf.yaml
│       ├── msbuild.yaml
│       ├── nanorc.yaml
│       ├── nftables.yaml
│       ├── nginx.yaml
│       ├── nim.yaml
│       ├── nix.yaml
│       ├── nu.yaml
│       ├── objc.yaml
│       ├── ocaml.yaml
│       ├── octave.yaml
│       ├── odin.yaml
│       ├── pascal.yaml
│       ├── patch.yaml
│       ├── peg.yaml
│       ├── perl.yaml
│       ├── php.yaml
│       ├── pkg-config.yaml
│       ├── po.yaml
│       ├── pony.yaml
│       ├── pov.yaml
│       ├── privoxy-action.yaml
│       ├── privoxy-config.yaml
│       ├── privoxy-filter.yaml
│       ├── proto.yaml
│       ├── prql.yaml
│       ├── puppet.yaml
│       ├── python2.yaml
│       ├── python3.yaml
│       ├── r.yaml
│       ├── raku.yaml
│       ├── reST.yaml
│       ├── renpy.yaml
│       ├── rpmspec.yaml
│       ├── ruby.yaml
│       ├── rust.yaml
│       ├── sage.yaml
│       ├── scad.yaml
│       ├── scala.yaml
│       ├── sed.yaml
│       ├── sh.yaml
│       ├── sls.yaml
│       ├── smalltalk.yaml
│       ├── solidity.yaml
│       ├── sql.yaml
│       ├── stata.yaml
│       ├── svelte.yaml
│       ├── swift.yaml
│       ├── syntax_converter.go
│       ├── systemd.yaml
│       ├── tcl.yaml
│       ├── terraform.yaml
│       ├── tex.yaml
│       ├── toml.yaml
│       ├── twig.yaml
│       ├── typescript.yaml
│       ├── v.yaml
│       ├── vala.yaml
│       ├── verilog.yaml
│       ├── vhdl.yaml
│       ├── vi.yaml
│       ├── vue.yaml
│       ├── xml.yaml
│       ├── xresources.yaml
│       ├── yaml.yaml
│       ├── yum.yaml
│       ├── zig.yaml
│       ├── zscript.yaml
│       └── zsh.yaml
├── snapcraft.yaml
└── tools/
    ├── build-date.go
    ├── build-version.go
    ├── compile-linux.sh
    ├── cross-compile.sh
    ├── info-plist.go
    ├── nightly-release.sh
    ├── package-deb.sh
    ├── pre-release.sh
    ├── release.sh
    ├── remove-nightly-assets.go
    ├── testgen.go
    ├── update-nightly-tag.sh
    └── vendor-src.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# See https://editorconfig.org

# In Go files we indent with tabs but still 
# set indent_size to control the GitHub web viewer.  
[*.go]
indent_size=4


================================================
FILE: .github/ISSUE_TEMPLATE/01-bug.yml
================================================
name: Bug Report
description: File a bug report.
title: "<title>"
labels: ["bug", "triage"]
body:
- type: textarea
  attributes:
    label: Description
    description: Description of the problem and steps to reproduce.
  validations:
    required: true
- type: textarea
  attributes:
    label: Environment
    description: |
      examples:
        - **Version**: 2.0.15 and/or commit hash ($ micro -version)
        - **OS**: Debian
        - **Terminal**: ptyxis
    value: |
        - Version:
        - OS:
        - Terminal:
  validations:
    required: true


================================================
FILE: .github/ISSUE_TEMPLATE/02-feature.yml
================================================
name: Feature Request
description: File a feature request.
title: "<title>"
labels: ["feature"]
body:
- type: textarea
  attributes:
    label: Description
    description: Description of the feature.
  validations:
    required: true


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false


================================================
FILE: .github/workflows/nightly.yaml
================================================
name: Nightly builds
on:
  workflow_dispatch: # Allows manual trigger
  schedule:
    - cron: '0 0 * * *'
jobs:
  nightly:
    strategy:
      matrix:
        go-version: [1.23.x]
        os: [ubuntu-latest]
    runs-on: ${{ matrix.os }}
    steps:
    - name: Setup
      uses: actions/setup-go@v5
      with:
        go-version: ${{ matrix.go-version }}
        cache: false

    - name: Checkout
      uses: actions/checkout@v4
      with:
        ref: master
        fetch-depth: 0
        fetch-tags: true

    - name: Build
      run: tools/cross-compile.sh nightly

    - name: Tag
      uses: rickstaa/action-create-tag@v1
      with:
        tag: nightly
        force_push_tag: true
        message: "Pre-release nightly"

    - name: Publish
      uses: softprops/action-gh-release@v2
      with:
        name: nightly
        tag_name: nightly
        files: binaries/*
        prerelease: true

    - name: Cleanup
      run: rm -rf binaries


================================================
FILE: .github/workflows/release.yaml
================================================
name: Release builds
on:
  workflow_dispatch: # Allows manual trigger
  # push:
  #   tags:
  #     - 'v*.*.*' # automatically react on semantic versioned tags
jobs:
  release:
    strategy:
      matrix:
        go-version: [1.23.x]
        os: [ubuntu-latest]
    runs-on: ${{ matrix.os }}
    steps:
    - name: Setup
      uses: actions/setup-go@v5
      with:
        go-version: ${{ matrix.go-version }}
        cache: false

    - name: Checkout
      uses: actions/checkout@v4
      with:
        fetch-depth: 0
        fetch-tags: true

    - name: Build
      run: tools/cross-compile.sh

    - name: Publish
      uses: softprops/action-gh-release@v2
      with:
        files: binaries/*

    - name: Cleanup
      run: rm -rf binaries


================================================
FILE: .github/workflows/test.yaml
================================================
on: [push, pull_request]
name: Build and Test
jobs:
  test:
    strategy:
      matrix:
        go-version: [1.19.x, 1.23.x]
        os: [ubuntu-latest, macos-latest, windows-latest]
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/setup-go@v5
      with:
        go-version: ${{ matrix.go-version }}
        cache: false

    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
        fetch-tags: true

    - name: Build
      run: |
        make build

    - name: Test
      run: |
        make test


================================================
FILE: .gitignore
================================================
.DS_Store

micro
micro.exe
!cmd/micro
binaries/
tmp.sh
test/
.idea/
packages/
todo.txt
test.txt
log.txt
*.old
benchmark_results*
tools/build-version
tools/build-date
tools/info-plist
tools/vscode-tests/
*.hdr


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2016-2020: Zachary Yedidia, et al.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: LICENSE-THIRD-PARTY
================================================
Third party libraries directly used by micro and their licenses
================

github.com/golang/go/LICENSE
================

Copyright (c) 2009 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
   * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

github.com/blang/semver/LICENSE
================

The MIT License

Copyright (c) 2014 Benedikt Lang <github at benediktlang.de>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


github.com/gdamore/encoding/LICENSE
================


                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


github.com/go-errors/errors/LICENSE.MIT
================

Copyright (c) 2015 Conrad Irwin <conrad@bugsnag.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


github.com/mattn/go-isatty/LICENSE
================

Copyright (c) Yasuhiro MATSUMOTO <mattn.jp@gmail.com>

MIT License (Expat)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


github.com/mattn/go-runewidth/LICENSE
================

The MIT License (MIT)

Copyright (c) 2016 Yasuhiro Matsumoto

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


github.com/mitchellh/go-homedir/LICENSE
================

The MIT License (MIT)

Copyright (c) 2013 Mitchell Hashimoto

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


github.com/sergi/go-diff/LICENSE
================

Copyright (c) 2012-2016 The go-diff Authors. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.



github.com/yuin/gopher-lua/LICENSE
================

The MIT License (MIT)

Copyright (c) 2015 Yusuke Inuzuka

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


github.com/atotto/clipboard/LICENSE
================
github.com/zyedidia/clipboard/LICENSE (fork)
================

Copyright (c) 2013 Ato Araki. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
   * Neither the name of @atotto. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


github.com/gdamore/tcell/LICENSE
================
github.com/micro-editor/tcell/LICENSE (fork)
================


                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


golang.org/x/text/LICENSE
================

Copyright (c) 2009 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
   * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


layeh.com/gopher-luar/LICENSE
================

Mozilla Public License Version 2.0
==================================

1. Definitions
--------------

1.1. "Contributor"
    means each individual or legal entity that creates, contributes to
    the creation of, or owns Covered Software.

1.2. "Contributor Version"
    means the combination of the Contributions of others (if any) used
    by a Contributor and that particular Contributor's Contribution.

1.3. "Contribution"
    means Covered Software of a particular Contributor.

1.4. "Covered Software"
    means Source Code Form to which the initial Contributor has attached
    the notice in Exhibit A, the Executable Form of such Source Code
    Form, and Modifications of such Source Code Form, in each case
    including portions thereof.

1.5. "Incompatible With Secondary Licenses"
    means

    (a) that the initial Contributor has attached the notice described
        in Exhibit B to the Covered Software; or

    (b) that the Covered Software was made available under the terms of
        version 1.1 or earlier of the License, but not also under the
        terms of a Secondary License.

1.6. "Executable Form"
    means any form of the work other than Source Code Form.

1.7. "Larger Work"
    means a work that combines Covered Software with other material, in 
    a separate file or files, that is not Covered Software.

1.8. "License"
    means this document.

1.9. "Licensable"
    means having the right to grant, to the maximum extent possible,
    whether at the time of the initial grant or subsequently, any and
    all of the rights conveyed by this License.

1.10. "Modifications"
    means any of the following:

    (a) any file in Source Code Form that results from an addition to,
        deletion from, or modification of the contents of Covered
        Software; or

    (b) any new file in Source Code Form that contains any Covered
        Software.

1.11. "Patent Claims" of a Contributor
    means any patent claim(s), including without limitation, method,
    process, and apparatus claims, in any patent Licensable by such
    Contributor that would be infringed, but for the grant of the
    License, by the making, using, selling, offering for sale, having
    made, import, or transfer of either its Contributions or its
    Contributor Version.

1.12. "Secondary License"
    means either the GNU General Public License, Version 2.0, the GNU
    Lesser General Public License, Version 2.1, the GNU Affero General
    Public License, Version 3.0, or any later versions of those
    licenses.

1.13. "Source Code Form"
    means the form of the work preferred for making modifications.

1.14. "You" (or "Your")
    means an individual or a legal entity exercising rights under this
    License. For legal entities, "You" includes any entity that
    controls, is controlled by, or is under common control with You. For
    purposes of this definition, "control" means (a) the power, direct
    or indirect, to cause the direction or management of such entity,
    whether by contract or otherwise, or (b) ownership of more than
    fifty percent (50%) of the outstanding shares or beneficial
    ownership of such entity.

2. License Grants and Conditions
--------------------------------

2.1. Grants

Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:

(a) under intellectual property rights (other than patent or trademark)
    Licensable by such Contributor to use, reproduce, make available,
    modify, display, perform, distribute, and otherwise exploit its
    Contributions, either on an unmodified basis, with Modifications, or
    as part of a Larger Work; and

(b) under Patent Claims of such Contributor to make, use, sell, offer
    for sale, have made, import, and otherwise transfer either its
    Contributions or its Contributor Version.

2.2. Effective Date

The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.

2.3. Limitations on Grant Scope

The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:

(a) for any code that a Contributor has removed from Covered Software;
    or

(b) for infringements caused by: (i) Your and any other third party's
    modifications of Covered Software, or (ii) the combination of its
    Contributions with other software (except as part of its Contributor
    Version); or

(c) under Patent Claims infringed by Covered Software in the absence of
    its Contributions.

This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).

2.4. Subsequent Licenses

No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).

2.5. Representation

Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.

2.6. Fair Use

This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.

2.7. Conditions

Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.

3. Responsibilities
-------------------

3.1. Distribution of Source Form

All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.

3.2. Distribution of Executable Form

If You distribute Covered Software in Executable Form then:

(a) such Covered Software must also be made available in Source Code
    Form, as described in Section 3.1, and You must inform recipients of
    the Executable Form how they can obtain a copy of such Source Code
    Form by reasonable means in a timely manner, at a charge no more
    than the cost of distribution to the recipient; and

(b) You may distribute such Executable Form under the terms of this
    License, or sublicense it under different terms, provided that the
    license for the Executable Form does not attempt to limit or alter
    the recipients' rights in the Source Code Form under this License.

3.3. Distribution of a Larger Work

You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).

3.4. Notices

You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.

3.5. Application of Additional Terms

You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.

4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------

If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.

5. Termination
--------------

5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.

5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.

5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.

************************************************************************
*                                                                      *
*  6. Disclaimer of Warranty                                           *
*  -------------------------                                           *
*                                                                      *
*  Covered Software is provided under this License on an "as is"       *
*  basis, without warranty of any kind, either expressed, implied, or  *
*  statutory, including, without limitation, warranties that the       *
*  Covered Software is free of defects, merchantable, fit for a        *
*  particular purpose or non-infringing. The entire risk as to the     *
*  quality and performance of the Covered Software is with You.        *
*  Should any Covered Software prove defective in any respect, You     *
*  (not any Contributor) assume the cost of any necessary servicing,   *
*  repair, or correction. This disclaimer of warranty constitutes an   *
*  essential part of this License. No use of any Covered Software is   *
*  authorized under this License except under this disclaimer.         *
*                                                                      *
************************************************************************

************************************************************************
*                                                                      *
*  7. Limitation of Liability                                          *
*  --------------------------                                          *
*                                                                      *
*  Under no circumstances and under no legal theory, whether tort      *
*  (including negligence), contract, or otherwise, shall any           *
*  Contributor, or anyone who distributes Covered Software as          *
*  permitted above, be liable to You for any direct, indirect,         *
*  special, incidental, or consequential damages of any character      *
*  including, without limitation, damages for lost profits, loss of    *
*  goodwill, work stoppage, computer failure or malfunction, or any    *
*  and all other commercial damages or losses, even if such party      *
*  shall have been informed of the possibility of such damages. This   *
*  limitation of liability shall not apply to liability for death or   *
*  personal injury resulting from such party's negligence to the       *
*  extent applicable law prohibits such limitation. Some               *
*  jurisdictions do not allow the exclusion or limitation of           *
*  incidental or consequential damages, so this exclusion and          *
*  limitation may not apply to You.                                    *
*                                                                      *
************************************************************************

8. Litigation
-------------

Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.

9. Miscellaneous
----------------

This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.

10. Versions of the License
---------------------------

10.1. New Versions

Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.

10.2. Effect of New Versions

You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.

10.3. Modified Versions

If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).

10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses

If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.

Exhibit A - Source Code Form License Notice
-------------------------------------------

  This Source Code Form is subject to the terms of the Mozilla Public
  License, v. 2.0. If a copy of the MPL was not distributed with this
  file, You can obtain one at http://mozilla.org/MPL/2.0/.

If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.

You may add additional accurate notices of copyright ownership.

Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------

  This Source Code Form is "Incompatible With Secondary Licenses", as
  defined by the Mozilla Public License, v. 2.0.

github.com/flynn/json5/LICENSE
================
github.com/micro-editor/json5/LICENSE (fork)
================

Decoder code based on package encoding/json from the Go language.

Copyright (c) 2012 The Go Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

   * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
   * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.



Test data based on the parse cases from https://github.com/json5/json5

Copyright (c) 2012-2016 Aseem Kishore, and others.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

github.com/james4k/terminal/LICENSE
================
github.com/micro-editor/terminal/LICENSE (fork)
================

Copyright (C) 2013 James Gray

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without liitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and thismssion notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

github.com/kr/pty/License
================
github.com/zyedidia/pty/License (fork)
================

Copyright (c) 2011 Keith Rarick

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall
be included in all copies or substantial portions of the
Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

github.com/npat-efault/poller/LICENSE.txt
================
github.com/zyedidia/poller/LICENSE.txt (fork)
================

Copyright (c) 2014, Nick Patavalis (npat@efault.net)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

github.com/zyedidia/glob
================

Glob is licensed under the MIT "Expat" License:

Copyright (c) 2016: Zachary Yedidia.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

github.com/dustin/go-humanize/LICENSE
================

Copyright (c) 2005-2008  Dustin Sallings <dustin@spy.net>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

<http://www.opensource.org/licenses/mit-license.php>

gopkg.in/yaml.v2/LICENSE
================

Copyright 2011-2016 Canonical Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

github.com/kballard/go-shellquote/LICENSE
===============

Copyright (C) 2014 Kevin Ballard

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

github.com/stretchr/testify
=================

MIT License

Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
.PHONY: runtime build generate build-quick

VERSION = $(shell GOOS=$(shell go env GOHOSTOS) GOARCH=$(shell go env GOHOSTARCH) \
	go run tools/build-version.go)
HASH = $(shell git rev-parse --short HEAD)
DATE = $(shell GOOS=$(shell go env GOHOSTOS) GOARCH=$(shell go env GOHOSTARCH) \
	go run tools/build-date.go)
GOBIN ?= $(shell go env GOPATH)/bin
GOVARS = -X github.com/micro-editor/micro/v2/internal/util.Version=$(VERSION) -X github.com/micro-editor/micro/v2/internal/util.CommitHash=$(HASH) -X 'github.com/micro-editor/micro/v2/internal/util.CompileDate=$(DATE)'
DEBUGVAR = -X github.com/micro-editor/micro/v2/internal/util.Debug=ON
VSCODE_TESTS_BASE_URL = 'https://raw.githubusercontent.com/microsoft/vscode/e6a45f4242ebddb7aa9a229f85555e8a3bd987e2/src/vs/editor/test/common/model/'
CGO_ENABLED := $(if $(CGO_ENABLED),$(CGO_ENABLED),0)

ADDITIONAL_GO_LINKER_FLAGS := ""
GOHOSTOS = $(shell go env GOHOSTOS)
ifeq ($(GOHOSTOS), darwin)
	# Native darwin resp. macOS builds need external and dynamic linking
	ADDITIONAL_GO_LINKER_FLAGS += $(shell GOOS=$(GOHOSTOS) \
		GOARCH=$(shell go env GOHOSTARCH) \
		go run tools/info-plist.go "$(shell go env GOOS)" "$(VERSION)")
	CGO_ENABLED = 1
endif

build: generate build-quick

build-quick:
	CGO_ENABLED=$(CGO_ENABLED) go build -trimpath -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro

build-dbg:
	CGO_ENABLED=$(CGO_ENABLED) go build -trimpath -ldflags "$(ADDITIONAL_GO_LINKER_FLAGS) $(DEBUGVAR)" ./cmd/micro

build-tags: fetch-tags build

build-all: build

install: generate
	go install -ldflags "-s -w $(GOVARS) $(ADDITIONAL_GO_LINKER_FLAGS)" ./cmd/micro

install-all: install

fetch-tags:
	git fetch --tags --force

generate:
	GOOS=$(shell go env GOHOSTOS) GOARCH=$(shell go env GOHOSTARCH) go generate ./runtime

testgen:
	mkdir -p tools/vscode-tests
	cd tools/vscode-tests && \
	curl --remote-name-all $(VSCODE_TESTS_BASE_URL){editableTextModelAuto,editableTextModel,model.line}.test.ts
	tsc tools/vscode-tests/*.ts > /dev/null; true
	go run tools/testgen.go tools/vscode-tests/*.js > buffer_generated_test.go
	mv buffer_generated_test.go internal/buffer
	gofmt -w internal/buffer/buffer_generated_test.go

test:
	go test ./internal/...
	go test ./cmd/...

bench:
	for i in 1 2 3; do \
		go test -bench=. ./internal/...; \
	done > benchmark_results
	benchstat benchmark_results

bench-baseline:
	for i in 1 2 3; do \
		go test -bench=. ./internal/...; \
	done > benchmark_results_baseline

bench-compare:
	for i in 1 2 3; do \
		go test -bench=. ./internal/...; \
	done > benchmark_results
	benchstat -alpha 0.15 benchmark_results_baseline benchmark_results

clean:
	rm -f micro


================================================
FILE: README.md
================================================
<img alt="micro logo" src="./assets/micro-logo-drop.svg" width="500px"/>

![Test Workflow](https://github.com/micro-editor/micro/actions/workflows/test.yaml/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/micro-editor/micro/v2)](https://goreportcard.com/report/github.com/micro-editor/micro/v2)
[![Release](https://img.shields.io/github/release/micro-editor/micro.svg?label=Release)](https://github.com/micro-editor/micro/releases)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/micro-editor/micro/blob/master/LICENSE)
[![Join the chat at https://gitter.im/zyedidia/micro](https://badges.gitter.im/zyedidia/micro.svg)](https://gitter.im/zyedidia/micro?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Snap Status](https://snapcraft.io/micro/badge.svg)](https://snapcraft.io/micro)

**micro** is a terminal-based text editor that aims to be easy to use and intuitive, while also taking advantage of the capabilities
of modern terminals. It comes as a single, batteries-included, static binary with no dependencies; you can download and use it right now!

As its name indicates, micro aims to be somewhat of a successor to the nano editor by being easy to install and use.
It strives to be enjoyable as a full-time editor for people who prefer to work in a terminal, or those who regularly edit files over SSH.

Here is a picture of micro editing its source code.

![Screenshot](./assets/micro-solarized.png)

To see more screenshots of micro, showcasing some of the default color schemes, see [here](https://micro-editor.github.io).

You can also check out the website for Micro at https://micro-editor.github.io.

- - -

## Features

- Easy to use and install.
- No dependencies or external files are needed — just the binary you can download further down the page.
- Multiple cursors.
- Common keybindings (<kbd>Ctrl-s</kbd>, <kbd>Ctrl-c</kbd>, <kbd>Ctrl-v</kbd>, <kbd>Ctrl-z</kbd>, …).
  - Keybindings can be rebound to your liking.
- Sane defaults.
  - You shouldn't have to configure much out of the box (and it is extremely easy to configure).
- Splits and tabs.
- nano-like menu to help you remember the keybindings.
- Extremely good mouse support.
  - This means mouse dragging to create a selection, double click to select by word, and triple click to select by line.
- Cross-platform (it should work on all the platforms Go runs on).
  - Note that while Windows is supported, Mingw/Cygwin is not (see below).
- Plugin system (plugins are written in Lua).
  - micro has a built-in plugin manager to automatically install, remove, and update plugins.
- Built-in diff gutter.
- Simple autocompletion.
- Persistent undo.
- Automatic linting and error notifications.
- Syntax highlighting for over [130 languages](runtime/syntax).
- Color scheme support.
  - By default, micro comes with 16, 256, and true color themes.
- True color support.
- Copy and paste with the system clipboard.
- Small and simple.
- Easily configurable.
- Macros.
- Smart highlighting of trailing whitespace and tab vs space errors.
- Common editor features such as undo/redo, line numbers, Unicode support, soft wrapping, …

## Installation

To install micro, you can download a [prebuilt binary](https://github.com/micro-editor/micro/releases), or you can build it from source.

If you want more information about ways to install micro, see this [wiki page](https://github.com/micro-editor/micro/wiki/Installing-Micro).

Use `micro -version` to get the version information after installing. It is only guaranteed that you are installing the most recent
stable version if you install from the prebuilt binaries, Homebrew, or Snap.

A desktop entry file and man page can be found in the [assets/packaging](https://github.com/micro-editor/micro/tree/master/assets/packaging) directory.

### Pre-built binaries

Pre-built binaries are distributed in [releases](https://github.com/micro-editor/micro/releases).

To uninstall micro, simply remove the binary, and the configuration directory at `~/.config/micro`.

#### Third-party quick-install script

```bash
curl https://getmic.ro | bash
```

The script will place the micro binary in the current directory. From there, you can move it to a directory on your path of your choosing (e.g. `sudo mv micro /usr/bin`). See its [GitHub repository](https://github.com/benweissmann/getmic.ro) for more information.

#### Eget

With [Eget](https://github.com/zyedidia/eget) installed, you can easily get a pre-built binary:

```
eget micro-editor/micro
```

Use `--tag VERSION` to download a specific tagged version.

```
eget --tag nightly micro-editor/micro # download the nightly version (compiled every day at midnight UTC)
eget --tag v2.0.8 micro-editor/micro  # download version 2.0.8 rather than the latest release
```

You can install `micro` by adding `--to /usr/local/bin` to the `eget` command, or move the binary manually to a directory on your `$PATH` after the download completes.

See [Eget](https://github.com/zyedidia/eget) for more information.

### Package managers

You can install micro using Homebrew on Mac:

```
brew install micro
```

**Note for Mac:** All micro keybindings use the control or alt (option) key, not the command
key. By default, macOS terminals do not forward alt key events. To fix this, please see
the section on [macOS terminals](https://github.com/micro-editor/micro#macos-terminal) further below.

On Linux, you can install micro through [snap](https://snapcraft.io/docs/core/install)

```
snap install micro --classic
```

Micro is also available through other package managers on Linux such as dnf, AUR, Nix, and package managers
for other operating systems. These packages are not guaranteed to be up-to-date.

<!-- * `apt install micro` (Ubuntu 20.04 `focal`, and Debian `unstable | testing | buster-backports`). At the moment, this package (2.0.1-1) is outdated and has a known bug where debug mode is enabled. -->

* Linux:
    * distro-specific package managers:
        * `dnf install micro` (Fedora).
        * `apt install micro` (Ubuntu and Debian).
        * `pacman -S micro` (Arch Linux).
        * `emerge app-editors/micro` (Gentoo).
        * `zypper install micro-editor` (SUSE)
        * `eopkg install micro` (Solus).
        * `pacstall -I micro` (Pacstall).
        * `apt-get install micro` (ALT Linux)
        * See [wiki](https://github.com/micro-editor/micro/wiki/Installing-Micro) for details about CRUX, Termux.
    * distro-agnostic package managers:
        * `nix profile install nixpkgs#micro` (with [Nix](https://nixos.org/) and flakes enabled)
        * `flox install micro` (with [Flox](https://flox.dev))
* Windows: [Chocolatey](https://chocolatey.org), [Scoop](https://scoop.sh/) and [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget/).
    * `choco install micro`.
    * `scoop install micro`.
    * `winget install zyedidia.micro`
* OpenBSD: Available in the ports tree and also available as a binary package.
    * `pkg_add -v micro`.
* NetBSD, macOS, Linux, Illumos, etc. with [pkgsrc](https://www.pkgsrc.org/)-current:
    * `pkg_add micro`
* macOS: Available in package managers.
    * `sudo port install micro` (with [MacPorts](https://www.macports.org))
    * `brew install micro` (with [Homebrew](https://brew.sh/))
    * `nix profile install nixpkgs#micro` (with [Nix](https://nixos.org/) and flakes enabled)
    * `flox install micro` (with [Flox](https://flox.dev))

**Note for Linux desktop environments:**

For interfacing with the local system clipboard, the following tools need to be installed:
* For X11, `xclip` or `xsel`
* For [Wayland](https://wayland.freedesktop.org/), `wl-clipboard`

Without these tools installed, micro will use an internal clipboard for copy and paste, but it won't be accessible to external applications.

### Building from source

If your operating system does not have a binary release, but does run Go, you can build from source.

Make sure that you have Go version 1.19 or greater and Go modules are enabled.

```
git clone https://github.com/micro-editor/micro
cd micro
make build
sudo mv micro /usr/local/bin # optional
```

The binary will be placed in the current directory and can be moved to
anywhere you like (for example `/usr/local/bin`).

The command `make install` will install the binary to `$GOPATH/bin` or `$GOBIN`.

You can install directly with `go get` (`go get github.com/micro-editor/micro/cmd/micro`) but this isn't
recommended because it doesn't build micro with version information (necessary for the plugin manager),
and doesn't disable debug mode.

### Fully static or dynamically linked binary

By default, the micro binary is linked statically to increase the portability of the prebuilt binaries.
This behavior can simply be overriden by providing `CGO_ENABLED=1` to the build target.

```
CGO_ENABLED=1 make build
```

Afterwards the micro binary will dynamically link with the present core system libraries.

**Note for Mac:**
Native macOS builds are done with `CGO_ENABLED=1` forced set to support adding the "Information Property List" in the linker step.

### macOS terminal

If you are using macOS, you should consider using [iTerm2](https://iterm2.com/) instead of the default terminal (Terminal.app). The iTerm2 terminal has much better mouse support as well as better handling of key events. For best keybinding behavior, choose `xterm defaults` under `Preferences->Profiles->Keys->Presets...`, and select `Esc+` for `Left Option Key` in the same menu. The newest versions also support true color.

If you still insist on using the default Mac terminal, be sure to set `Use Option key as Meta key` under
`Preferences->Profiles->Keyboard` to use <kbd>option</kbd> as <kbd>alt</kbd>.

### WSL and Windows Console

If you use micro within WSL, it is highly recommended that you use the [Windows
Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701?hl=en-us&gl=us)
instead of the default Windows Console.

If you must use Windows Console for some reason, note that there is a bug in
Windows Console WSL that causes a font change whenever micro tries to access
the external clipboard via powershell. To fix this, use an internal clipboard
with `set clipboard internal` (though your system clipboard will no longer be
available in micro).

### Colors and syntax highlighting

If you open micro and it doesn't seem like syntax highlighting is working, this is probably because
you are using a terminal which does not support 256 color mode. Try changing the color scheme to `simple`
by pressing <kbd>Ctrl-e</kbd> in micro and typing `set colorscheme simple`.

If you are using the default Ubuntu terminal, to enable 256 color mode make sure your `TERM` variable is set
to `xterm-256color`.

Many of the Windows terminals don't support more than 16 colors, which means
that micro's default color scheme won't look very good. You can either set
the color scheme to `simple`, or download and configure a better terminal emulator
than the Windows default.

### Cygwin, Mingw, Plan9

Cygwin, Mingw, and Plan9 are unfortunately not officially supported. In Cygwin and Mingw, micro will often work when run using
the `winpty` utility:

```
winpty micro.exe ...
```

Micro uses the amazing [tcell library](https://github.com/gdamore/tcell), but this
means that micro is restricted to the platforms tcell supports. As a result, micro does not support
Plan9 or Cygwin (although this may change in the future). Micro also doesn't support NaCl (which is deprecated anyway).

## Usage

Once you have built the editor, start it by running `micro path/to/file.txt` or `micro` to open an empty buffer.

micro also supports creating buffers from `stdin`:

```sh
ip a | micro
```

You can move the cursor around with the arrow keys and mouse.

You can also use the mouse to manipulate the text. Simply clicking and dragging
will select text. You can also double click to enable word selection, and triple
click to enable line selection.

## Documentation and Help

micro has a built-in help system which you can access by pressing <kbd>Ctrl-e</kbd> and typing `help`. Additionally, you can
view the help files here:

- [main help](https://github.com/micro-editor/micro/tree/master/runtime/help/help.md)
- [keybindings](https://github.com/micro-editor/micro/tree/master/runtime/help/keybindings.md)
- [commands](https://github.com/micro-editor/micro/tree/master/runtime/help/commands.md)
- [colors](https://github.com/micro-editor/micro/tree/master/runtime/help/colors.md)
- [options](https://github.com/micro-editor/micro/tree/master/runtime/help/options.md)
- [plugins](https://github.com/micro-editor/micro/tree/master/runtime/help/plugins.md)

I also recommend reading the [tutorial](https://github.com/micro-editor/micro/tree/master/runtime/help/tutorial.md) for
a brief introduction to the more powerful configuration features micro offers.

There is also an unofficial Discord, which you can join at https://discord.gg/nhWR6armnR.

## Contributing

If you find any bugs, please report them! I am also happy to accept pull requests from anyone.

You can use the [GitHub issue tracker](https://github.com/micro-editor/micro/issues)
to report bugs, ask questions, or suggest new features.

For a more informal setting to discuss the editor, you can join the [Gitter chat](https://gitter.im/zyedidia/micro) or the [Discord](https://discord.gg/nhWR6armnR). You can also use the [Discussions](https://github.com/micro-editor/micro/discussions) section on Github for a forum-like setting or for Q&A.

Sometimes I am unresponsive, and I apologize! If that happens, please ping me.


================================================
FILE: assets/packaging/deb/micro.postinst
================================================
#!/bin/sh

set -e

if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
    update-alternatives --install /usr/bin/editor editor /usr/bin/micro 40 \
      --slave /usr/share/man/man1/editor.1 editor.1 \
      /usr/share/man/man1/micro.1
fi


================================================
FILE: assets/packaging/deb/micro.prerm
================================================
#!/bin/sh

set -e

if [ "$1" != "upgrade" ]; then
    update-alternatives --remove editor /usr/bin/micro
fi


================================================
FILE: assets/packaging/micro.1
================================================
.TH micro 1 "2025-09-03"
.SH NAME
micro \- A modern and intuitive terminal-based text editor
.SH SYNOPSIS
.B micro
.RI [ OPTION ]...\&
.RI [ FILE ]...\&
.RI [+ LINE [: COL ]]\&
.RI [+/ REGEX ]
.br
.B micro
.RI [ OPTION ]...\&
.RI [ FILE [: LINE [: COL ]]]...\&
\& (only if the `parsecursor` option is enabled)
.SH DESCRIPTION
Micro is a terminal-based text editor that aims to be easy to use and intuitive, while also taking advantage of the full capabilities
of modern terminals. It comes as one single, batteries-included, static binary with no dependencies.

As the name indicates, micro aims to be somewhat of a successor to the nano editor by being easy to install and use in a pinch, but micro also aims to be
enjoyable to use full time, whether you work in the terminal because you prefer it (like me), or because you need to (over ssh).

Use Ctrl-q to quit, Ctrl-s to save, and Ctrl-g to open the in-editor help menu.
.SH OPTIONS
.PP
.B \-clean
.RS 4
Clean the configuration directory and exit
.RE
.PP
.B \-config-dir
.I dir
.RS 4
Specify a custom location for the configuration directory
.RE
.PP
.IR FILE : LINE [: COL ]
(only if the `parsecursor` option is enabled)
.br
.IR FILE \ + LINE [: COL ]
.RS 4
Specify a line and column to start the cursor at when opening a buffer
.RE
.PP
.RI +/ REGEX
.RS 4
Specify a regex to search for when opening a buffer
.RE
.PP
.B \-options
.RS 4
Show all options help and exit
.RE
.PP
.B \-debug
.RS 4
Enable debug mode (enables logging to ./log.txt)
.RE
.PP
.B \-profile
.RS 4
Enable CPU profiling (writes profile info to ./micro.prof so it can be analyzed later with "go tool pprof micro.prof")
.RE
.PP
.B \-version
.RS 4
Show the version number and information and exit
.RE

Micro's plugins can be managed at the command line with the following commands.
.RS 4
.PP
.B \-plugin install
.RI [ PLUGIN ]...
.RS 4
Install plugin(s)
.RE
.PP
.B \-plugin remove
.RI [ PLUGIN ]...
.RS 4
Remove plugin(s)
.RE
.PP
.B \-plugin update
.RI [ PLUGIN ]...
.RS 4
Update plugin(s) (if no argument is given, updates all plugins)
.RE
.PP
.B \-plugin search
.RI [ PLUGIN ]...
.RS 4
Search for a plugin
.RE
.PP
.B \-plugin list
.RS 4
List installed plugins
.RE
.PP
.B \-plugin available
.RS 4
List available plugins
.RE
.RE

Micro's options can also be set via command line arguments for quick
adjustments. For real configuration, please use the settings.json
file (see 'help options').
.RS 4
.PP
.BI \-< option >
.I value
.RS 4
Set `option` to `value` for this session.
.br
For example: `micro -syntax off file.c`
.RE
.RE
.PP
Use `micro -options` to see the full list of configuration options.
.SH CONFIGURATION
Micro uses $MICRO_CONFIG_HOME as the configuration directory.
If this environment variable is not set, it uses $XDG_CONFIG_HOME/micro instead.
If that environment variable is not set, it uses ~/.config/micro as the configuration directory.
In the documentation, we use ~/.config/micro to refer to the configuration directory
(even if it may in fact be somewhere else if you have set either of the above environment variables).
.SH NOTICE
This manpage is intended only to serve as a quick guide to the invocation of 
micro and is not intended to replace the full documentation included with micro
which can be accessed from within micro. Micro tells you what key combination to
press to get help in the lower right.
.SH BUGS
A comprehensive list of bugs will not be listed in this manpage. See the Github
page at \fBhttps://github.com/micro-editor/micro/issues\fP for a list of known bugs
and to report any newly encountered bugs you may find. We strive to correct
bugs as swiftly as possible.
.SH COPYRIGHT
Copyright \(co 2020 Zachary Yedidia, et al. MIT license.
See \fBhttps://github.com/micro-editor/micro\fP for details.


================================================
FILE: assets/packaging/micro.desktop
================================================
[Desktop Entry]

Name=Micro
GenericName=Text Editor
Comment=Edit text files in a terminal

Icon=micro
Type=Application
Categories=Utility;TextEditor;Development;
Keywords=text;editor;syntax;terminal;

Exec=micro %F
StartupNotify=false
Terminal=true
MimeType=text/plain;text/x-chdr;text/x-csrc;text/x-c++hdr;text/x-c++src;text/x-java;text/x-dsrc;text/x-pascal;text/x-perl;text/x-python;application/x-php;application/x-httpd-php3;application/x-httpd-php4;application/x-httpd-php5;application/xml;text/html;text/css;text/x-sql;text/x-diff;


================================================
FILE: cmd/micro/clean.go
================================================
package main

import (
	"bufio"
	"encoding/gob"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"

	"github.com/micro-editor/micro/v2/internal/buffer"
	"github.com/micro-editor/micro/v2/internal/config"
	"github.com/micro-editor/micro/v2/internal/util"
)

func shouldContinue() bool {
	reader := bufio.NewReader(os.Stdin)
	fmt.Print("Continue [Y/n]: ")
	text, err := reader.ReadString('\n')
	if err != nil {
		fmt.Println(err)
		return false
	}

	text = strings.TrimRight(text, "\r\n")

	return len(text) == 0 || strings.ToLower(text)[0] == 'y'
}

// CleanConfig performs cleanup in the user's configuration directory
func CleanConfig() {
	fmt.Println("Cleaning your configuration directory at", config.ConfigDir)
	fmt.Printf("Please consider backing up %s before continuing\n", config.ConfigDir)

	if !shouldContinue() {
		fmt.Println("Stopping early")
		return
	}

	fmt.Println("Cleaning default settings")

	settingsFile := filepath.Join(config.ConfigDir, "settings.json")
	err := config.WriteSettings(settingsFile)
	if err != nil {
		if errors.Is(err, util.ErrOverwrite) {
			fmt.Println(err.Error())
		} else {
			fmt.Println("Error writing settings.json file: " + err.Error())
		}
	}

	// detect unused options
	var unusedOptions []string
	defaultSettings := config.DefaultAllSettings()
	for k := range config.GlobalSettings {
		if _, ok := defaultSettings[k]; !ok {
			valid := false
			for _, p := range config.Plugins {
				if strings.HasPrefix(k, p.Name+".") || k == p.Name {
					valid = true
				}
			}
			if !valid {
				unusedOptions = append(unusedOptions, k)
			}
		}
	}

	if len(unusedOptions) > 0 {
		fmt.Println("The following options are unused:")

		sort.Strings(unusedOptions)

		for _, s := range unusedOptions {
			fmt.Printf("%s (value: %v)\n", s, config.GlobalSettings[s])
		}

		fmt.Printf("These options will be removed from %s\n", settingsFile)

		if shouldContinue() {
			for _, s := range unusedOptions {
				delete(config.GlobalSettings, s)
			}

			err := config.OverwriteSettings(settingsFile)
			if err != nil {
				if errors.Is(err, util.ErrOverwrite) {
					fmt.Println(err.Error())
				} else {
					fmt.Println("Error overwriting settings.json file: " + err.Error())
				}
			}

			fmt.Println("Removed unused options")
			fmt.Print("\n\n")
		}
	}

	// detect incorrectly formatted buffer/ files
	buffersPath := filepath.Join(config.ConfigDir, "buffers")
	files, err := os.ReadDir(buffersPath)
	if err == nil {
		var badFiles []string
		var buffer buffer.SerializedBuffer
		for _, f := range files {
			fname := filepath.Join(buffersPath, f.Name())
			file, e := os.Open(fname)

			if e == nil {
				decoder := gob.NewDecoder(file)
				err = decoder.Decode(&buffer)

				if err != nil && f.Name() != "history" {
					badFiles = append(badFiles, fname)
				}
				file.Close()
			}
		}

		if len(badFiles) > 0 {
			fmt.Printf("Detected %d files with an invalid format in %s\n", len(badFiles), buffersPath)
			fmt.Println("These files store cursor and undo history.")
			fmt.Printf("Removing badly formatted files in %s\n", buffersPath)

			if shouldContinue() {
				removed := 0
				for _, f := range badFiles {
					err := os.Remove(f)
					if err != nil {
						fmt.Println(err)
						continue
					}
					removed++
				}

				if removed == 0 {
					fmt.Println("Failed to remove files")
				} else {
					fmt.Printf("Removed %d badly formatted files\n", removed)
				}
				fmt.Print("\n\n")
			}
		}
	}

	// detect plugins/ directory
	plugins := filepath.Join(config.ConfigDir, "plugins")
	if stat, err := os.Stat(plugins); err == nil && stat.IsDir() {
		fmt.Printf("Found directory %s\n", plugins)
		fmt.Printf("Plugins should now be stored in %s\n", filepath.Join(config.ConfigDir, "plug"))
		fmt.Printf("Removing %s\n", plugins)

		if shouldContinue() {
			os.RemoveAll(plugins)
		}

		fmt.Print("\n\n")
	}

	fmt.Println("Done cleaning")
}


================================================
FILE: cmd/micro/debug.go
================================================
package main

import (
	"log"
	"os"

	"github.com/micro-editor/micro/v2/internal/util"
)

// NullWriter simply sends writes into the void
type NullWriter struct{}

// Write is empty
func (NullWriter) Write(data []byte) (n int, err error) {
	return 0, nil
}

// InitLog sets up the debug log system for micro if it has been enabled by compile-time variables
func InitLog() {
	if util.Debug == "ON" {
		f, err := os.OpenFile("log.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, util.FileMode)
		if err != nil {
			log.Fatalf("error opening file: %v", err)
		}

		log.SetOutput(f)
		log.Println("Micro started")
	} else {
		log.SetOutput(NullWriter{})
	}
}


================================================
FILE: cmd/micro/initlua.go
================================================
package main

import (
	"log"
	"time"

	lua "github.com/yuin/gopher-lua"
	luar "layeh.com/gopher-luar"

	"github.com/micro-editor/micro/v2/internal/action"
	"github.com/micro-editor/micro/v2/internal/buffer"
	"github.com/micro-editor/micro/v2/internal/config"
	"github.com/micro-editor/micro/v2/internal/display"
	ulua "github.com/micro-editor/micro/v2/internal/lua"
	"github.com/micro-editor/micro/v2/internal/screen"
	"github.com/micro-editor/micro/v2/internal/shell"
	"github.com/micro-editor/micro/v2/internal/util"
)

func init() {
	ulua.L = lua.NewState()
	ulua.L.SetGlobal("import", luar.New(ulua.L, LuaImport))
}

// LuaImport is meant to be called from lua by a plugin and will import the given micro package
func LuaImport(pkg string) *lua.LTable {
	switch pkg {
	case "micro":
		return luaImportMicro()
	case "micro/shell":
		return luaImportMicroShell()
	case "micro/buffer":
		return luaImportMicroBuffer()
	case "micro/config":
		return luaImportMicroConfig()
	case "micro/util":
		return luaImportMicroUtil()
	default:
		return ulua.Import(pkg)
	}
}

func luaImportMicro() *lua.LTable {
	pkg := ulua.L.NewTable()

	ulua.L.SetField(pkg, "TermMessage", luar.New(ulua.L, screen.TermMessage))
	ulua.L.SetField(pkg, "TermError", luar.New(ulua.L, screen.TermError))
	ulua.L.SetField(pkg, "InfoBar", luar.New(ulua.L, action.GetInfoBar))
	ulua.L.SetField(pkg, "Log", luar.New(ulua.L, log.Println))
	ulua.L.SetField(pkg, "SetStatusInfoFn", luar.New(ulua.L, display.SetStatusInfoFnLua))
	ulua.L.SetField(pkg, "CurPane", luar.New(ulua.L, func() *action.BufPane {
		return action.MainTab().CurPane()
	}))
	ulua.L.SetField(pkg, "CurTab", luar.New(ulua.L, action.MainTab))
	ulua.L.SetField(pkg, "Tabs", luar.New(ulua.L, func() *action.TabList {
		return action.Tabs
	}))
	ulua.L.SetField(pkg, "After", luar.New(ulua.L, func(t time.Duration, f func()) {
		time.AfterFunc(t, func() {
			timerChan <- f
		})
	}))

	return pkg
}

func luaImportMicroConfig() *lua.LTable {
	pkg := ulua.L.NewTable()

	ulua.L.SetField(pkg, "MakeCommand", luar.New(ulua.L, action.MakeCommand))
	ulua.L.SetField(pkg, "FileComplete", luar.New(ulua.L, buffer.FileComplete))
	ulua.L.SetField(pkg, "HelpComplete", luar.New(ulua.L, action.HelpComplete))
	ulua.L.SetField(pkg, "OptionComplete", luar.New(ulua.L, action.OptionComplete))
	ulua.L.SetField(pkg, "OptionValueComplete", luar.New(ulua.L, action.OptionValueComplete))
	ulua.L.SetField(pkg, "NoComplete", luar.New(ulua.L, nil))
	ulua.L.SetField(pkg, "TryBindKey", luar.New(ulua.L, action.TryBindKeyPlug))
	ulua.L.SetField(pkg, "Reload", luar.New(ulua.L, action.ReloadConfig))
	ulua.L.SetField(pkg, "AddRuntimeFileFromMemory", luar.New(ulua.L, config.PluginAddRuntimeFileFromMemory))
	ulua.L.SetField(pkg, "AddRuntimeFilesFromDirectory", luar.New(ulua.L, config.PluginAddRuntimeFilesFromDirectory))
	ulua.L.SetField(pkg, "AddRuntimeFile", luar.New(ulua.L, config.PluginAddRuntimeFile))
	ulua.L.SetField(pkg, "ListRuntimeFiles", luar.New(ulua.L, config.PluginListRuntimeFiles))
	ulua.L.SetField(pkg, "ReadRuntimeFile", luar.New(ulua.L, config.PluginReadRuntimeFile))
	ulua.L.SetField(pkg, "NewRTFiletype", luar.New(ulua.L, config.NewRTFiletype))
	ulua.L.SetField(pkg, "RTColorscheme", luar.New(ulua.L, config.RTColorscheme))
	ulua.L.SetField(pkg, "RTSyntax", luar.New(ulua.L, config.RTSyntax))
	ulua.L.SetField(pkg, "RTHelp", luar.New(ulua.L, config.RTHelp))
	ulua.L.SetField(pkg, "RTPlugin", luar.New(ulua.L, config.RTPlugin))
	ulua.L.SetField(pkg, "RegisterCommonOption", luar.New(ulua.L, config.RegisterCommonOptionPlug))
	ulua.L.SetField(pkg, "RegisterGlobalOption", luar.New(ulua.L, config.RegisterGlobalOptionPlug))
	ulua.L.SetField(pkg, "GetGlobalOption", luar.New(ulua.L, config.GetGlobalOption))
	ulua.L.SetField(pkg, "SetGlobalOption", luar.New(ulua.L, action.SetGlobalOptionPlug))
	ulua.L.SetField(pkg, "SetGlobalOptionNative", luar.New(ulua.L, action.SetGlobalOptionNativePlug))
	ulua.L.SetField(pkg, "ConfigDir", luar.New(ulua.L, config.ConfigDir))

	return pkg
}

func luaImportMicroShell() *lua.LTable {
	pkg := ulua.L.NewTable()

	ulua.L.SetField(pkg, "ExecCommand", luar.New(ulua.L, shell.ExecCommand))
	ulua.L.SetField(pkg, "RunCommand", luar.New(ulua.L, shell.RunCommand))
	ulua.L.SetField(pkg, "RunBackgroundShell", luar.New(ulua.L, shell.RunBackgroundShell))
	ulua.L.SetField(pkg, "RunInteractiveShell", luar.New(ulua.L, shell.RunInteractiveShell))
	ulua.L.SetField(pkg, "JobStart", luar.New(ulua.L, shell.JobStart))
	ulua.L.SetField(pkg, "JobSpawn", luar.New(ulua.L, shell.JobSpawn))
	ulua.L.SetField(pkg, "JobStop", luar.New(ulua.L, shell.JobStop))
	ulua.L.SetField(pkg, "JobSend", luar.New(ulua.L, shell.JobSend))
	ulua.L.SetField(pkg, "RunTermEmulator", luar.New(ulua.L, action.RunTermEmulator))
	ulua.L.SetField(pkg, "TermEmuSupported", luar.New(ulua.L, action.TermEmuSupported))

	return pkg
}

func luaImportMicroBuffer() *lua.LTable {
	pkg := ulua.L.NewTable()

	ulua.L.SetField(pkg, "NewMessage", luar.New(ulua.L, buffer.NewMessage))
	ulua.L.SetField(pkg, "NewMessageAtLine", luar.New(ulua.L, buffer.NewMessageAtLine))
	ulua.L.SetField(pkg, "MTInfo", luar.New(ulua.L, buffer.MTInfo))
	ulua.L.SetField(pkg, "MTWarning", luar.New(ulua.L, buffer.MTWarning))
	ulua.L.SetField(pkg, "MTError", luar.New(ulua.L, buffer.MTError))
	ulua.L.SetField(pkg, "Loc", luar.New(ulua.L, func(x, y int) buffer.Loc {
		return buffer.Loc{x, y}
	}))
	ulua.L.SetField(pkg, "SLoc", luar.New(ulua.L, func(line, row int) display.SLoc {
		return display.SLoc{line, row}
	}))
	ulua.L.SetField(pkg, "BTDefault", luar.New(ulua.L, buffer.BTDefault.Kind))
	ulua.L.SetField(pkg, "BTHelp", luar.New(ulua.L, buffer.BTHelp.Kind))
	ulua.L.SetField(pkg, "BTLog", luar.New(ulua.L, buffer.BTLog.Kind))
	ulua.L.SetField(pkg, "BTScratch", luar.New(ulua.L, buffer.BTScratch.Kind))
	ulua.L.SetField(pkg, "BTRaw", luar.New(ulua.L, buffer.BTRaw.Kind))
	ulua.L.SetField(pkg, "BTInfo", luar.New(ulua.L, buffer.BTInfo.Kind))
	ulua.L.SetField(pkg, "NewBuffer", luar.New(ulua.L, func(text, path string) *buffer.Buffer {
		return buffer.NewBufferFromString(text, path, buffer.BTDefault)
	}))
	ulua.L.SetField(pkg, "NewBufferFromFile", luar.New(ulua.L, func(path string) (*buffer.Buffer, error) {
		return buffer.NewBufferFromFile(path, buffer.BTDefault)
	}))
	ulua.L.SetField(pkg, "ByteOffset", luar.New(ulua.L, buffer.ByteOffset))
	ulua.L.SetField(pkg, "Log", luar.New(ulua.L, buffer.WriteLog))
	ulua.L.SetField(pkg, "LogBuf", luar.New(ulua.L, buffer.GetLogBuf))

	return pkg
}

func luaImportMicroUtil() *lua.LTable {
	pkg := ulua.L.NewTable()

	ulua.L.SetField(pkg, "RuneAt", luar.New(ulua.L, util.LuaRuneAt))
	ulua.L.SetField(pkg, "GetLeadingWhitespace", luar.New(ulua.L, util.LuaGetLeadingWhitespace))
	ulua.L.SetField(pkg, "IsWordChar", luar.New(ulua.L, util.LuaIsWordChar))
	ulua.L.SetField(pkg, "String", luar.New(ulua.L, util.String))
	ulua.L.SetField(pkg, "Unzip", luar.New(ulua.L, util.Unzip))
	ulua.L.SetField(pkg, "Version", luar.New(ulua.L, util.Version))
	ulua.L.SetField(pkg, "SemVersion", luar.New(ulua.L, util.SemVersion))
	ulua.L.SetField(pkg, "HttpRequest", luar.New(ulua.L, util.HttpRequest))
	ulua.L.SetField(pkg, "CharacterCountInString", luar.New(ulua.L, util.CharacterCountInString))
	ulua.L.SetField(pkg, "RuneStr", luar.New(ulua.L, func(r rune) string {
		return string(r)
	}))

	return pkg
}


================================================
FILE: cmd/micro/micro.go
================================================
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"regexp"
	"runtime"
	"runtime/pprof"
	"sort"
	"strconv"
	"syscall"
	"time"

	"github.com/go-errors/errors"
	isatty "github.com/mattn/go-isatty"
	"github.com/micro-editor/micro/v2/internal/action"
	"github.com/micro-editor/micro/v2/internal/buffer"
	"github.com/micro-editor/micro/v2/internal/clipboard"
	"github.com/micro-editor/micro/v2/internal/config"
	"github.com/micro-editor/micro/v2/internal/screen"
	"github.com/micro-editor/micro/v2/internal/shell"
	"github.com/micro-editor/micro/v2/internal/util"
	"github.com/micro-editor/tcell/v2"
	lua "github.com/yuin/gopher-lua"
)

var (
	// Command line flags
	flagVersion   = flag.Bool("version", false, "Show the version number and information")
	flagConfigDir = flag.String("config-dir", "", "Specify a custom location for the configuration directory")
	flagOptions   = flag.Bool("options", false, "Show all option help")
	flagDebug     = flag.Bool("debug", false, "Enable debug mode (prints debug info to ./log.txt)")
	flagProfile   = flag.Bool("profile", false, "Enable CPU profiling (writes profile info to ./micro.prof)")
	flagPlugin    = flag.String("plugin", "", "Plugin command")
	flagClean     = flag.Bool("clean", false, "Clean configuration directory")
	optionFlags   map[string]*string

	sighup chan os.Signal

	timerChan chan func()
)

func InitFlags() {
	// Note: keep this in sync with the man page in assets/packaging/micro.1
	flag.Usage = func() {
		fmt.Println("Usage: micro [OPTION]... [FILE]... [+LINE[:COL]] [+/REGEX]")
		fmt.Println("       micro [OPTION]... [FILE[:LINE[:COL]]]...  (only if the `parsecursor` option is enabled)")
		fmt.Println("-clean")
		fmt.Println("    \tClean the configuration directory and exit")
		fmt.Println("-config-dir dir")
		fmt.Println("    \tSpecify a custom location for the configuration directory")
		fmt.Println("FILE:LINE[:COL] (only if the `parsecursor` option is enabled)")
		fmt.Println("FILE +LINE[:COL]")
		fmt.Println("    \tSpecify a line and column to start the cursor at when opening a buffer")
		fmt.Println("+/REGEX")
		fmt.Println("    \tSpecify a regex to search for when opening a buffer")
		fmt.Println("-options")
		fmt.Println("    \tShow all options help and exit")
		fmt.Println("-debug")
		fmt.Println("    \tEnable debug mode (enables logging to ./log.txt)")
		fmt.Println("-profile")
		fmt.Println("    \tEnable CPU profiling (writes profile info to ./micro.prof")
		fmt.Println("    \tso it can be analyzed later with \"go tool pprof micro.prof\")")
		fmt.Println("-version")
		fmt.Println("    \tShow the version number and information and exit")

		fmt.Print("\nMicro's plugins can be managed at the command line with the following commands.\n")
		fmt.Println("-plugin install [PLUGIN]...")
		fmt.Println("    \tInstall plugin(s)")
		fmt.Println("-plugin remove [PLUGIN]...")
		fmt.Println("    \tRemove plugin(s)")
		fmt.Println("-plugin update [PLUGIN]...")
		fmt.Println("    \tUpdate plugin(s) (if no argument is given, updates all plugins)")
		fmt.Println("-plugin search [PLUGIN]...")
		fmt.Println("    \tSearch for a plugin")
		fmt.Println("-plugin list")
		fmt.Println("    \tList installed plugins")
		fmt.Println("-plugin available")
		fmt.Println("    \tList available plugins")

		fmt.Print("\nMicro's options can also be set via command line arguments for quick\nadjustments. For real configuration, please use the settings.json\nfile (see 'help options').\n\n")
		fmt.Println("-<option> value")
		fmt.Println("    \tSet `option` to `value` for this session")
		fmt.Println("    \tFor example: `micro -syntax off file.c`")
		fmt.Println("\nUse `micro -options` to see the full list of configuration options")
	}

	optionFlags = make(map[string]*string)

	for k, v := range config.DefaultAllSettings() {
		optionFlags[k] = flag.String(k, "", fmt.Sprintf("The %s option. Default value: '%v'.", k, v))
	}

	flag.Parse()

	if *flagVersion {
		// If -version was passed
		fmt.Println("Version:", util.Version)
		fmt.Println("Commit hash:", util.CommitHash)
		fmt.Println("Compiled on", util.CompileDate)
		exit(0)
	}

	if *flagOptions {
		// If -options was passed
		var keys []string
		m := config.DefaultAllSettings()
		for k := range m {
			keys = append(keys, k)
		}
		sort.Strings(keys)
		for _, k := range keys {
			v := m[k]
			fmt.Printf("-%s value\n", k)
			fmt.Printf("    \tDefault value: '%v'\n", v)
		}
		exit(0)
	}

	if util.Debug == "OFF" && *flagDebug {
		util.Debug = "ON"
	}
}

// DoPluginFlags parses and executes any flags that require LoadAllPlugins (-plugin and -clean)
func DoPluginFlags() {
	if *flagClean || *flagPlugin != "" {
		config.LoadAllPlugins()

		if *flagPlugin != "" {
			args := flag.Args()

			config.PluginCommand(os.Stdout, *flagPlugin, args)
		} else if *flagClean {
			CleanConfig()
		}

		exit(0)
	}
}

// LoadInput determines which files should be loaded into buffers
// based on the input stored in flag.Args()
func LoadInput(args []string) []*buffer.Buffer {
	// There are a number of ways micro should start given its input

	// 1. If it is given a files in flag.Args(), it should open those

	// 2. If there is no input file and the input is not a terminal, that means
	// something is being piped in and the stdin should be opened in an
	// empty buffer

	// 3. If there is no input file and the input is a terminal, an empty buffer
	// should be opened

	buffers := make([]*buffer.Buffer, 0, len(args))

	files := make([]string, 0, len(args))

	flagStartPos := buffer.Loc{-1, -1}
	posFlagr := regexp.MustCompile(`^\+(\d+)(?::(\d+))?$`)
	posIndex := -1

	searchText := ""
	searchFlagr := regexp.MustCompile(`^\+\/(.+)$`)
	searchIndex := -1

	for i, a := range args {
		posMatch := posFlagr.FindStringSubmatch(a)
		if len(posMatch) == 3 && posMatch[2] != "" {
			line, err := strconv.Atoi(posMatch[1])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			col, err := strconv.Atoi(posMatch[2])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			flagStartPos = buffer.Loc{col - 1, line - 1}
			posIndex = i
		} else if len(posMatch) == 3 && posMatch[2] == "" {
			line, err := strconv.Atoi(posMatch[1])
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			flagStartPos = buffer.Loc{0, line - 1}
			posIndex = i
		} else {
			searchMatch := searchFlagr.FindStringSubmatch(a)
			if len(searchMatch) == 2 {
				searchText = searchMatch[1]
				searchIndex = i
			} else {
				files = append(files, a)
			}
		}
	}

	command := buffer.Command{
		StartCursor:      flagStartPos,
		SearchRegex:      searchText,
		SearchAfterStart: searchIndex > posIndex,
	}

	if len(files) > 0 {
		// Option 1
		// We go through each file and load it
		for i := 0; i < len(files); i++ {
			buf, err := buffer.NewBufferFromFileWithCommand(files[i], buffer.BTDefault, command)
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			// If the file didn't exist, input will be empty, and we'll open an empty buffer
			buffers = append(buffers, buf)
		}
	} else {
		btype := buffer.BTDefault
		if !isatty.IsTerminal(os.Stdout.Fd()) {
			btype = buffer.BTStdout
		}

		if !isatty.IsTerminal(os.Stdin.Fd()) {
			// Option 2
			// The input is not a terminal, so something is being piped in
			// and we should read from stdin
			input, err := io.ReadAll(os.Stdin)
			if err != nil {
				screen.TermMessage("Error reading from stdin: ", err)
				input = []byte{}
			}
			buffers = append(buffers, buffer.NewBufferFromStringWithCommand(string(input), "", btype, command))
		} else {
			// Option 3, just open an empty buffer
			buffers = append(buffers, buffer.NewBufferFromStringWithCommand("", "", btype, command))
		}
	}

	return buffers
}

func checkBackup(name string) error {
	target := filepath.Join(config.ConfigDir, name)
	backup := target + util.BackupSuffix
	if info, err := os.Stat(backup); err == nil {
		input, err := os.ReadFile(backup)
		if err == nil {
			t := info.ModTime()
			msg := fmt.Sprintf(buffer.BackupMsg, target, t.Format("Mon Jan _2 at 15:04, 2006"), backup)
			choice := screen.TermPrompt(msg, []string{"r", "i", "a", "recover", "ignore", "abort"}, true)

			if choice%3 == 0 {
				// recover
				err := os.WriteFile(target, input, util.FileMode)
				if err != nil {
					return err
				}
				return os.Remove(backup)
			} else if choice%3 == 1 {
				// delete
				return os.Remove(backup)
			} else if choice%3 == 2 {
				// abort
				return errors.New("Aborted")
			}
		}
	}
	return nil
}

func exit(rc int) {
	for _, b := range buffer.OpenBuffers {
		if !b.Modified() {
			b.Fini()
		}
	}

	if screen.Screen != nil {
		screen.Screen.Fini()
	}

	os.Exit(rc)
}

func main() {
	defer func() {
		if util.Stdout.Len() > 0 {
			fmt.Fprint(os.Stdout, util.Stdout.String())
		}
		exit(0)
	}()

	var err error

	InitFlags()

	if *flagProfile {
		f, err := os.Create("micro.prof")
		if err != nil {
			log.Fatal("error creating CPU profile: ", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("error starting CPU profile: ", err)
		}
		defer pprof.StopCPUProfile()
	}

	InitLog()

	err = config.InitConfigDir(*flagConfigDir)
	if err != nil {
		screen.TermMessage(err)
	}

	config.InitRuntimeFiles(true)
	config.InitPlugins()

	err = checkBackup("settings.json")
	if err != nil {
		screen.TermMessage(err)
		exit(1)
	}

	err = config.ReadSettings()
	if err != nil {
		screen.TermMessage(err)
	}
	err = config.InitGlobalSettings()
	if err != nil {
		screen.TermMessage(err)
	}

	// flag options
	for k, v := range optionFlags {
		if *v != "" {
			nativeValue, err := config.GetNativeValue(k, *v)
			if err != nil {
				screen.TermMessage(err)
				continue
			}
			if err = config.OptionIsValid(k, nativeValue); err != nil {
				screen.TermMessage(err)
				continue
			}
			config.GlobalSettings[k] = nativeValue
			config.VolatileSettings[k] = true
		}
	}

	DoPluginFlags()

	err = screen.Init()
	if err != nil {
		fmt.Println(err)
		fmt.Println("Fatal: Micro could not initialize a Screen.")
		exit(1)
	}

	util.Sigterm = make(chan os.Signal, 1)
	sighup = make(chan os.Signal, 1)
	signal.Notify(util.Sigterm, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGABRT)
	signal.Notify(sighup, syscall.SIGHUP)

	m := clipboard.SetMethod(config.GetGlobalOption("clipboard").(string))
	clipErr := clipboard.Initialize(m)

	defer func() {
		if err := recover(); err != nil {
			if screen.Screen != nil {
				screen.Screen.Fini()
			}
			if e, ok := err.(*lua.ApiError); ok {
				fmt.Println("Lua API error:", e)
			} else {
				fmt.Println("Micro encountered an error:", errors.Wrap(err, 2).ErrorStack(), "\nIf you can reproduce this error, please report it at https://github.com/micro-editor/micro/issues")
			}
			// immediately backup all buffers with unsaved changes
			for _, b := range buffer.OpenBuffers {
				if b.Modified() {
					b.Backup()
				}
			}
			exit(1)
		}
	}()

	err = config.LoadAllPlugins()
	if err != nil {
		screen.TermMessage(err)
	}

	err = checkBackup("bindings.json")
	if err != nil {
		screen.TermMessage(err)
		exit(1)
	}

	action.InitBindings()
	action.InitCommands()

	timerChan = make(chan func())

	err = config.RunPluginFn("preinit")
	if err != nil {
		screen.TermMessage(err)
	}

	action.InitGlobals()
	buffer.SetMessager(action.InfoBar)
	args := flag.Args()
	b := LoadInput(args)

	if len(b) == 0 {
		// No buffers to open
		screen.Screen.Fini()
		runtime.Goexit()
	}

	action.InitTabs(b)

	err = config.RunPluginFn("init")
	if err != nil {
		screen.TermMessage(err)
	}

	err = config.RunPluginFn("postinit")
	if err != nil {
		screen.TermMessage(err)
	}

	err = config.InitColorscheme()
	if err != nil {
		screen.TermMessage(err)
	}

	if clipErr != nil {
		log.Println(clipErr, " or change 'clipboard' option")
	}

	config.StartAutoSave()
	if a := config.GetGlobalOption("autosave").(float64); a > 0 {
		config.SetAutoTime(a)
	}

	screen.Events = make(chan tcell.Event)

	// Here is the event loop which runs in a separate thread
	go func() {
		for {
			screen.Lock()
			e := screen.Screen.PollEvent()
			screen.Unlock()
			if e != nil {
				screen.Events <- e
			}
		}
	}()

	// clear the drawchan so we don't redraw excessively
	// if someone requested a redraw before we started displaying
	for len(screen.DrawChan()) > 0 {
		<-screen.DrawChan()
	}

	// wait for initial resize event
	select {
	case event := <-screen.Events:
		action.Tabs.HandleEvent(event)
	case <-time.After(10 * time.Millisecond):
		// time out after 10ms
	}

	for {
		DoEvent()
	}
}

// DoEvent runs the main action loop of the editor
func DoEvent() {
	var event tcell.Event

	// Display everything
	screen.Screen.Fill(' ', config.DefStyle)
	screen.Screen.HideCursor()
	action.Tabs.Display()
	for _, ep := range action.MainTab().Panes {
		ep.Display()
	}
	action.MainTab().Display()
	action.InfoBar.Display()
	screen.Screen.Show()

	// Check for new events
	select {
	case f := <-shell.Jobs:
		// If a new job has finished while running in the background we should execute the callback
		f.Function(f.Output, f.Args)
	case <-config.Autosave:
		for _, b := range buffer.OpenBuffers {
			b.AutoSave()
		}
	case <-shell.CloseTerms:
		action.Tabs.CloseTerms()
	case event = <-screen.Events:
	case <-screen.DrawChan():
		for len(screen.DrawChan()) > 0 {
			<-screen.DrawChan()
		}
	case f := <-timerChan:
		f()
	case <-sighup:
		exit(0)
	case <-util.Sigterm:
		exit(0)
	}

	if e, ok := event.(*tcell.EventError); ok {
		log.Println("tcell event error: ", e.Error())

		if e.Err() == io.EOF {
			// shutdown due to terminal closing/becoming inaccessible
			exit(0)
		}
		return
	}

	if event != nil {
		_, resize := event.(*tcell.EventResize)
		if resize {
			action.InfoBar.HandleEvent(event)
			action.Tabs.HandleEvent(event)
		} else if action.InfoBar.HasPrompt {
			action.InfoBar.HandleEvent(event)
		} else {
			action.Tabs.HandleEvent(event)
		}
	}

	err := config.RunPluginFn("onAnyEvent")
	if err != nil {
		screen.TermMessage(err)
	}
}


================================================
FILE: cmd/micro/micro_test.go
================================================
package main

import (
	"fmt"
	"log"
	"os"
	"testing"

	"github.com/go-errors/errors"
	"github.com/micro-editor/micro/v2/internal/action"
	"github.com/micro-editor/micro/v2/internal/buffer"
	"github.com/micro-editor/micro/v2/internal/config"
	"github.com/micro-editor/micro/v2/internal/screen"
	"github.com/micro-editor/tcell/v2"
	"github.com/stretchr/testify/assert"
)

var tempDir string
var sim tcell.SimulationScreen

func init() {
	screen.Events = make(chan tcell.Event, 8)
}

func startup(args []string) (tcell.SimulationScreen, error) {
	var err error

	tempDir, err = os.MkdirTemp("", "micro_test")
	if err != nil {
		return nil, err
	}
	err = config.InitConfigDir(tempDir)
	if err != nil {
		return nil, err
	}

	config.InitRuntimeFiles(true)
	config.InitPlugins()

	err = config.ReadSettings()
	if err != nil {
		return nil, err
	}
	err = config.InitGlobalSettings()
	if err != nil {
		return nil, err
	}

	s, err := screen.InitSimScreen()
	if err != nil {
		return nil, err
	}

	defer func() {
		if err := recover(); err != nil {
			screen.Screen.Fini()
			fmt.Println("Micro encountered an error:", err)
			// immediately backup all buffers with unsaved changes
			for _, b := range buffer.OpenBuffers {
				if b.Modified() {
					b.Backup()
				}
			}
			// Print the stack trace too
			log.Fatalf(errors.Wrap(err, 2).ErrorStack())
		}
	}()

	err = config.LoadAllPlugins()
	if err != nil {
		screen.TermMessage(err)
	}

	action.InitBindings()
	action.InitCommands()

	err = config.InitColorscheme()
	if err != nil {
		return nil, err
	}

	b := LoadInput(args)

	if len(b) == 0 {
		return nil, errors.New("No buffers opened")
	}

	action.InitTabs(b)
	action.InitGlobals()

	err = config.RunPluginFn("init")
	if err != nil {
		return nil, err
	}

	s.InjectResize()
	handleEvent()

	return s, nil
}

func cleanup() {
	os.RemoveAll(tempDir)
}

func handleEvent() {
	screen.Lock()
	e := screen.Screen.PollEvent()
	screen.Unlock()
	if e != nil {
		screen.Events <- e
	}

	for len(screen.DrawChan()) > 0 || len(screen.Events) > 0 {
		DoEvent()
	}
}

func injectKey(key tcell.Key, r rune, mod tcell.ModMask) {
	sim.InjectKey(key, r, mod)
	handleEvent()
}

func injectMouse(x, y int, buttons tcell.ButtonMask, mod tcell.ModMask) {
	sim.InjectMouse(x, y, buttons, mod)
	handleEvent()
}

func injectString(str string) {
	// the tcell simulation screen event channel can only handle
	// 10 events at once, so we need to divide up the key events
	// into chunks of 10 and handle the 10 events before sending
	// another chunk of events
	iters := len(str) / 10
	extra := len(str) % 10

	for i := 0; i < iters; i++ {
		s := i * 10
		e := i*10 + 10
		sim.InjectKeyBytes([]byte(str[s:e]))
		for i := 0; i < 10; i++ {
			handleEvent()
		}
	}

	sim.InjectKeyBytes([]byte(str[len(str)-extra:]))
	for i := 0; i < extra; i++ {
		handleEvent()
	}
}

func openFile(file string) {
	injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl)
	injectString(fmt.Sprintf("open %s", file))
	injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
}

func findBuffer(file string) *buffer.Buffer {
	var buf *buffer.Buffer
	for _, b := range buffer.OpenBuffers {
		if b.Path == file {
			buf = b
		}
	}
	return buf
}

func createTestFile(t *testing.T, content string) string {
	f, err := os.CreateTemp(t.TempDir(), "")
	if err != nil {
		t.Fatal(err)
	}
	defer func() {
		if err := f.Close(); err != nil {
			t.Fatal(err)
		}
	}()

	if _, err := f.WriteString(content); err != nil {
		t.Fatal(err)
	}

	return f.Name()
}

func TestMain(m *testing.M) {
	var err error
	sim, err = startup([]string{})
	if err != nil {
		log.Fatalln(err)
	}

	retval := m.Run()
	cleanup()

	os.Exit(retval)
}

func TestSimpleEdit(t *testing.T) {
	file := createTestFile(t, "base content")

	openFile(file)

	if findBuffer(file) == nil {
		t.Fatalf("Could not find buffer %s", file)
	}

	injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
	injectKey(tcell.KeyUp, 0, tcell.ModNone)
	injectString("first line")

	// test both kinds of backspace
	for i := 0; i < len("ne"); i++ {
		injectKey(tcell.KeyBackspace, rune(tcell.KeyBackspace), tcell.ModNone)
	}
	for i := 0; i < len(" li"); i++ {
		injectKey(tcell.KeyBackspace2, rune(tcell.KeyBackspace2), tcell.ModNone)
	}
	injectString("foobar")

	injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl)

	data, err := os.ReadFile(file)
	if err != nil {
		t.Fatal(err)
	}

	assert.Equal(t, "firstfoobar\nbase content\n", string(data))
}

func TestMouse(t *testing.T) {
	file := createTestFile(t, "base content")

	openFile(file)

	if findBuffer(file) == nil {
		t.Fatalf("Could not find buffer %s", file)
	}

	// buffer:
	// base content
	// the selections need to happen at different locations to avoid a double click
	injectMouse(3, 0, tcell.Button1, tcell.ModNone)
	injectKey(tcell.KeyLeft, 0, tcell.ModNone)
	injectMouse(0, 0, tcell.ButtonNone, tcell.ModNone)
	injectString("secondline")
	// buffer:
	// secondlinebase content
	injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
	// buffer:
	// secondline
	// base content
	injectMouse(2, 0, tcell.Button1, tcell.ModNone)
	injectMouse(0, 0, tcell.ButtonNone, tcell.ModNone)
	injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
	// buffer:
	//
	// secondline
	// base content
	injectKey(tcell.KeyUp, 0, tcell.ModNone)
	injectString("firstline")
	// buffer:
	// firstline
	// secondline
	// base content
	injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl)

	data, err := os.ReadFile(file)
	if err != nil {
		t.Fatal(err)
	}

	assert.Equal(t, "firstline\nsecondline\nbase content\n", string(data))
}

var srTestStart = `foo
foo
foofoofoo
Ernleȝe foo æðelen
`
var srTest2 = `test_string
test_string
test_stringtest_stringtest_string
Ernleȝe test_string æðelen
`
var srTest3 = `test_foo
test_string
test_footest_stringtest_foo
Ernleȝe test_string æðelen
`

func TestSearchAndReplace(t *testing.T) {
	file := createTestFile(t, srTestStart)

	openFile(file)

	if findBuffer(file) == nil {
		t.Fatalf("Could not find buffer %s", file)
	}

	injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl)
	injectString(fmt.Sprintf("replaceall %s %s", "foo", "test_string"))
	injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)

	injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl)

	data, err := os.ReadFile(file)
	if err != nil {
		t.Fatal(err)
	}

	assert.Equal(t, srTest2, string(data))

	injectKey(tcell.KeyCtrlE, rune(tcell.KeyCtrlE), tcell.ModCtrl)
	injectString(fmt.Sprintf("replace %s %s", "string", "foo"))
	injectKey(tcell.KeyEnter, rune(tcell.KeyEnter), tcell.ModNone)
	injectString("ynyny")
	injectKey(tcell.KeyEscape, 0, tcell.ModNone)

	injectKey(tcell.KeyCtrlS, rune(tcell.KeyCtrlS), tcell.ModCtrl)

	data, err = os.ReadFile(file)
	if err != nil {
		t.Fatal(err)
	}

	assert.Equal(t, srTest3, string(data))
}

func TestMultiCursor(t *testing.T) {
	// TODO
}

func TestSettingsPersistence(t *testing.T) {
	// TODO
}

// more tests (rendering, tabs, plugins)?


================================================
FILE: data/io.github.zyedidia.micro.metainfo.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
	<id>io.github.zyedidia.micro</id>
	<launchable type="desktop-id">micro.desktop</launchable>
	<name>Micro Text Editor</name>
	<summary>A modern and intuitive terminal-based text editor</summary>
	<description>
		<p>
			micro is a terminal-based text editor that aims to be easy to use and
			intuitive, while also taking advantage of the capabilities of modern terminals.
			It comes as a single, batteries-included, static binary with no dependencies;
			you can download and use it right now!
		</p>
		<p>
			As its name indicates, micro aims to be somewhat of a successor to the nano
			editor by being easy to install and use. It strives to be enjoyable as a full-time
			editor for people who prefer to work in a terminal, or those who regularly
			edit files over SSH.
		</p>
	</description>
	<metadata_license>MIT</metadata_license>
	<project_license>MIT</project_license>
	<categories>
		<category>Development</category>
		<category>TextEditor</category>
	</categories>
	<releases>
			<release version="2.0.15" date="2025-12-31"/>
			<release version="2.0.14" date="2024-08-27"/>
			<release version="2.0.13" date="2023-10-22"/>
			<release version="2.0.12" date="2023-09-06"/>
			<release version="2.0.11" date="2022-08-01"/>
	</releases>
	<provides>
		<binary>micro</binary>
		<id>com.github.zyedidia.micro</id>
	</provides>
	<developer_name>Zachary Yedidia</developer_name>
	<screenshots>
		<screenshot type="default">
			<caption>Micro Text Editor editing its source code</caption>
			<image type="source">https://raw.githubusercontent.com/micro-editor/micro/master/assets/micro-solarized.png</image>
		</screenshot>
	</screenshots>
	<content_rating type="oars-1.1" />
	<url type="homepage">https://micro-editor.github.io</url>
	<url type="bugtracker">https://github.com/micro-editor/micro/issues</url>
	<url type="faq">https://micro-editor.github.io/about.html</url>
	<url type="help">https://micro-editor.github.io/about.html</url>
	<url type="contact">https://github.com/zyedidia</url>
	<url type="vcs-browser">https://github.com/micro-editor/micro</url>
	<url type="contribute">https://github.com/micro-editor/micro#contributing</url>
</component>


================================================
FILE: data/micro.json
================================================
{
    "$comment": "https://github.com/micro-editor/micro",
    "$schema": "http://json-schema.org/draft-07/schema#",
    "title": "options",
    "description": "A micro editor config schema",
    "type": "object",
    "properties": {
        "autoindent": {
            "description": "Whether to use the same indentation as a previous line\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "autosave": {
            "description": "A delay between automatic saves\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "integer",
            "minimum": 0,
            "default": 0
        },
        "autosu": {
            "description": "Whether attempt to use super user privileges\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "backup": {
            "description": "Whether to backup all open buffers\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "backupdir": {
            "description": "A directory to store backups\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "default": ""
        },
        "basename": {
            "description": "Whether to show a basename instead of a full path\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "clipboard": {
            "description": "A way to access the system clipboard\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "enum": [
                "external",
                "terminal",
                "internal"
            ],
            "default": "external"
        },
        "colorcolumn": {
            "description": "A position to display a column\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "integer",
            "minimum": 0,
            "default": 0
        },
        "colorscheme": {
            "description": "A color scheme\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "enum": [
                "atom-dark",
                "bubblegum",
                "cmc-16",
                "cmc-tc",
                "darcula",
                "default",
                "dracula-tc",
                "dukedark-tc",
                "dukelight-tc",
                "dukeubuntu-tc",
                "geany",
                "gotham",
                "gruvbox",
                "gruvbox-tc",
                "material-tc",
                "monokai-dark",
                "monokai",
                "one-dark",
                "railscast",
                "simple",
                "solarized",
                "solarized-tc",
                "sunny-day",
                "twilight",
                "zenburn"
            ],
            "default": "default"
        },
        "cursorline": {
            "description": "Whether to highlight a line with a cursor with a different color\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "diffgutter": {
            "description": "Whether to display diff inticators before lines\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "divchars": {
            "description": "Divider chars for vertical and horizontal splits\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "default": "|-"
        },
        "divreverse": {
            "description": "Whether to use inversed color scheme colors for splits\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "encoding": {
            "description": "An encoding used to open and save files\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "default": "utf-8"
        },
        "eofnewline": {
            "description": "Whether to add a missing trailing new line\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "fastdirty": {
            "description": "Whether to use a fast algorithm to determine whether a file is changed\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "fileformat": {
            "description": "A line ending format\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "enum": [
                "unix",
                "dos"
            ],
            "default": "unix"
        },
        "filetype": {
            "description": "A filetype for the current buffer\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "default": "unknown"
        },
        "hlsearch": {
            "description": "Whether to highlight all instances of a searched text after a successful search\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "incsearch": {
            "description": "Whether to enable an incremental search in `Find` prompt\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "ignorecase": {
            "description": "Whether to perform case-insensitive searches\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "indentchar": {
            "description": "An indentation character\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "maxLength": 1,
            "default": " "
        },
        "infobar": {
            "description": "Whether to enable a line at the bottom where messages are printed\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "keepautoindent": {
            "description": "Whether add a whitespace while using autoindent\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "keymenu": {
            "description": "Whether to display nano-style key menu at the bottom\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "matchbrace": {
            "description": "Whether to show matching braces\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "matchbracestyle": {
            "description": "Whether to underline or highlight matching braces\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "enum": [
                "underline",
                "highlight"
            ],
            "default": "underline"
        },
        "mkparents": {
            "description": "Whether to create missing directories\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "mouse": {
            "description": "Whether to enable mouse support\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "paste": {
            "description": "Whether to treat characters sent from the terminal in a single chunk as a paste event\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "parsecursor": {
            "description": "Whether to extract a line number and a column to open files with from file names\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "permbackup": {
            "description": "Whether to permanently save backups\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "pluginchannels": {
            "description": "A file with list of plugin channels\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "default": "https://raw.githubusercontent.com/micro-editor/plugin-channel/master/channel.json"
        },
        "pluginrepos": {
            "description": "Plugin repositories\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "array",
            "uniqueItems": true,
            "items": {
                "description": "A pluging repository\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
                "type": "string"
            },
            "default": []
        },
        "readonly": {
            "description": "Whether to forbid buffer editing\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "rmtrailingws": {
            "description": "Whether to remove trailing whitespaces\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "ruler": {
            "description": "Whether to display line numbers\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "relativeruler": {
            "description": "Whether to display relative line numbers\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "savecursor": {
            "description": "Whether to save cursor position in files\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "savehistory": {
            "description": "Whether to save command history between closing and re-opening editor\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "saveundo": {
            "description": "Whether to save undo after closing file\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "scrollbar": {
            "description": "Whether to save undo after closing file\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "scrollmargin": {
            "description": "A margin at which a view starts scrolling when a cursor approaches an edge of a view\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "integer",
            "default": 3
        },
        "scrollspeed": {
            "description": "Line count to scroll for one scroll event\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "integer",
            "default": 2
        },
        "smartpaste": {
            "description": "Whether to add a leading whitespace while pasting multiple lines\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "softwrap": {
            "description": "Whether to wrap long lines\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "splitbottom": {
            "description": "Whether to create a new horizontal split below the current one\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "splitright": {
            "description": "Whether to create a new vertical split right of the current one\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "statusformatl": {
            "description": "Format string of left-justified part of the statusline\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "default": "$(filename) $(modified)($(line),$(col)) $(status.paste)| ft:$(opt:filetype) | $(opt:fileformat) | $(opt:encoding)"
        },
        "statusformatr": {
            "description": "Format string of right-justified part of the statusline\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "default": "$(bind:ToggleKeyMenu): bindings, $(bind:ToggleHelp): help"
        },
        "statusline": {
            "description": "Whether to display a status line\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "sucmd": {
            "description": "A super user command\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "string",
            "default": "sudo",
            "examples": [
                "sudo",
                "doas"
            ]
        },
        "syntax": {
            "description": "Whether to enable a syntax highlighting\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "tabmovement": {
            "description": "Whether to navigate spaces at the beginning of lines as if they are tabs\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "tabhighlight": {
            "description": "Whether to invert tab character colors\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "tabreverse": {
            "description": "Whether to reverse tab bar colors\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "tabsize": {
            "description": "A tab size\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "integer",
            "default": 4
        },
        "tabstospaces": {
            "description": "Whether to use spaces instead of tabs\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "useprimary": {
            "description": "Whether to use primary clipboard to copy selections in the background\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": true
        },
        "wordwrap": {
            "description": "Whether to wrap long lines by words\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        },
        "xterm": {
            "description": "Whether to assume that the current terminal is `xterm`\nhttps://github.com/micro-editor/micro/blob/master/runtime/help/options.md#options",
            "type": "boolean",
            "default": false
        }
    },
    "additionalProperties": false
}


================================================
FILE: go.mod
================================================
module github.com/micro-editor/micro/v2

require (
	github.com/blang/semver v3.5.1+incompatible
	github.com/dustin/go-humanize v1.0.0
	github.com/go-errors/errors v1.0.1
	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
	github.com/mattn/go-isatty v0.0.20
	github.com/mattn/go-runewidth v0.0.16
	github.com/micro-editor/json5 v1.0.1-micro
	github.com/micro-editor/tcell/v2 v2.0.13
	github.com/micro-editor/terminal v0.0.0-20250324214352-e587e959c6b5
	github.com/mitchellh/go-homedir v1.1.0
	github.com/sergi/go-diff v1.1.0
	github.com/stretchr/testify v1.4.0
	github.com/yuin/gopher-lua v1.1.1
	github.com/zyedidia/clipper v0.1.1
	github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3
	golang.org/x/text v0.4.0
	gopkg.in/yaml.v2 v2.2.8
	layeh.com/gopher-luar v1.0.11
)

require (
	github.com/creack/pty v1.1.18 // indirect
	github.com/davecgh/go-spew v1.1.1 // indirect
	github.com/gdamore/encoding v1.0.0 // indirect
	github.com/lucasb-eyer/go-colorful v1.0.3 // indirect
	github.com/pmezard/go-difflib v1.0.0 // indirect
	github.com/rivo/uniseg v0.2.0 // indirect
	github.com/zyedidia/poller v1.0.1 // indirect
	golang.org/x/sys v0.30.0 // indirect
	golang.org/x/term v0.29.0 // indirect
)

replace github.com/kballard/go-shellquote => github.com/micro-editor/go-shellquote v0.0.0-20250101105543-feb6c39314f5

replace layeh.com/gopher-luar v1.0.11 => github.com/layeh/gopher-luar v1.0.11

go 1.19


================================================
FILE: go.sum
================================================
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/layeh/gopher-luar v1.0.11 h1:ss6t9OtykOiETBScJylSMPhuYAtOmpH5rSX10/wCcis=
github.com/layeh/gopher-luar v1.0.11/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk=
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/micro-editor/go-shellquote v0.0.0-20250101105543-feb6c39314f5 h1:D7BPnsedXiKo/e8RTFX419/52ICNhU8UKPQGZ/0yiLc=
github.com/micro-editor/go-shellquote v0.0.0-20250101105543-feb6c39314f5/go.mod h1:zaPgW/fDiW4MUfEwxpC+GB/bhvX44NJaNHmRAC9auHQ=
github.com/micro-editor/json5 v1.0.1-micro h1:5Y4MuzhkmW0sQQNPvrIVevIOKi557qsznwjRr4iq1AI=
github.com/micro-editor/json5 v1.0.1-micro/go.mod h1:cmlPHZ1JKOXNse0/3zwwKj/GUpzAVkzx4lZDkpHl4q0=
github.com/micro-editor/tcell/v2 v2.0.13 h1:xyuSpBhSBsUH+bs7FER9IV2/TsQpBmCFiNWJVAEdT68=
github.com/micro-editor/tcell/v2 v2.0.13/go.mod h1:ixpjICpoGp83FZVoLYFJPBwCAslHeTnvgPdhJVPLyy0=
github.com/micro-editor/terminal v0.0.0-20250324214352-e587e959c6b5 h1:czSkYUNmHuWS2lv8VreufENEXZNOCGZcXd744YKf8yM=
github.com/micro-editor/terminal v0.0.0-20250324214352-e587e959c6b5/go.mod h1:OszIG7ockt4osicVHq6gI2QmV4PBDK6H5/Bj8GDGv4Q=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/robertkrimen/otto v0.2.1 h1:FVP0PJ0AHIjC+N4pKCG9yCDz6LHNPCwi/GKID5pGGF0=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
github.com/zyedidia/clipper v0.1.1 h1:HBgguFNDq/QmSQKBnhy4sMKzILINr139VEgAhftOUTw=
github.com/zyedidia/clipper v0.1.1/go.mod h1:7YApPNiiTZTXdKKZG92G50qj6mnWEX975Sdu65J7YpQ=
github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3 h1:oMHjjTLfGXVuyOQBYj5/td9WC0mw4g1xDBPovIqmHew=
github.com/zyedidia/glob v0.0.0-20170209203856-dd4023a66dc3/go.mod h1:YKbIYP//Eln8eDgAJGI3IDvR3s4Tv9Z9TGIOumiyQ5c=
github.com/zyedidia/poller v1.0.1 h1:Tt9S3AxAjXwWGNiC2TUdRJkQDZSzCBNVQ4xXiQ7440s=
github.com/zyedidia/poller v1.0.1/go.mod h1:vZXJOHGDcuK08GXhF6IAY0ZFd2WcgOR5DOTp84Uk5eE=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=


================================================
FILE: internal/action/actions.go
================================================
package action

import (
	"errors"
	"fmt"
	"io/fs"
	"os"
	"regexp"
	"runtime"
	"strings"
	"time"

	shellquote "github.com/kballard/go-shellquote"
	"github.com/micro-editor/micro/v2/internal/buffer"
	"github.com/micro-editor/micro/v2/internal/clipboard"
	"github.com/micro-editor/micro/v2/internal/config"
	"github.com/micro-editor/micro/v2/internal/display"
	"github.com/micro-editor/micro/v2/internal/screen"
	"github.com/micro-editor/micro/v2/internal/shell"
	"github.com/micro-editor/micro/v2/internal/util"
	"github.com/micro-editor/tcell/v2"
)

// ScrollUp is not an action
func (h *BufPane) ScrollUp(n int) {
	v := h.GetView()
	v.StartLine = h.Scroll(v.StartLine, -n)
	h.SetView(v)
}

// ScrollDown is not an action
func (h *BufPane) ScrollDown(n int) {
	v := h.GetView()
	v.StartLine = h.Scroll(v.StartLine, n)
	h.SetView(v)
}

// ScrollAdjust can be used to shift the view so that the last line is at the
// bottom if the user has scrolled past the last line.
func (h *BufPane) ScrollAdjust() {
	v := h.GetView()
	end := h.SLocFromLoc(h.Buf.End())
	if h.Diff(v.StartLine, end) < h.BufView().Height-1 {
		v.StartLine = h.Scroll(end, -h.BufView().Height+1)
	}
	h.SetView(v)
}

// ScrollReachedEnd returns true if the view is at the end of the buffer,
// i.e. the last line of the buffer is in the view.
func (h *BufPane) ScrollReachedEnd() bool {
	v := h.GetView()
	end := h.SLocFromLoc(h.Buf.End())
	return h.Diff(v.StartLine, end) < h.BufView().Height
}

// MousePress is the event that should happen when a normal click happens
// This is almost always bound to left click
func (h *BufPane) MousePress(e *tcell.EventMouse) bool {
	b := h.Buf
	mx, my := e.Position()
	// ignore click on the status line
	if my >= h.BufView().Y+h.BufView().Height {
		return false
	}
	mouseLoc := h.LocFromVisual(buffer.Loc{mx, my})
	h.Cursor.Loc = mouseLoc

	if b.NumCursors() > 1 {
		b.ClearCursors()
		h.Relocate()
		h.Cursor = h.Buf.GetActiveCursor()
		h.Cursor.Loc = mouseLoc
	}
	if time.Since(h.lastClickTime)/time.Millisecond < config.DoubleClickThreshold && (mouseLoc.X == h.lastLoc.X && mouseLoc.Y == h.lastLoc.Y) {
		if h.DoubleClick {
			// Triple click
			h.lastClickTime = time.Now()

			h.TripleClick = true
			h.DoubleClick = false

			h.Cursor.SelectLine()
			h.Cursor.CopySelection(clipboard.PrimaryReg)
		} else {
			// Double click
			h.lastClickTime = time.Now()

			h.DoubleClick = true
			h.TripleClick = false

			h.Cursor.SelectWord()
			h.Cursor.CopySelection(clipboard.PrimaryReg)
		}
	} else {
		h.DoubleClick = false
		h.TripleClick = false
		h.lastClickTime = time.Now()

		h.Cursor.OrigSelection[0] = h.Cursor.Loc
		h.Cursor.CurSelection[0] = h.Cursor.Loc
		h.Cursor.CurSelection[1] = h.Cursor.Loc
	}

	h.Cursor.StoreVisualX()
	h.lastLoc = mouseLoc
	h.Relocate()
	return true
}

func (h *BufPane) MouseDrag(e *tcell.EventMouse) bool {
	mx, my := e.Position()
	// ignore drag on the status line
	if my >= h.BufView().Y+h.BufView().Height {
		return false
	}
	h.Cursor.Loc = h.LocFromVisual(buffer.Loc{mx, my})

	if h.TripleClick {
		h.Cursor.AddLineToSelection()
	} else if h.DoubleClick {
		h.Cursor.AddWordToSelection()
	} else {
		h.Cursor.SelectTo(h.Cursor.Loc)
	}

	h.Cursor.StoreVisualX()
	h.Relocate()
	return true
}

func (h *BufPane) MouseRelease(e *tcell.EventMouse) bool {
	// We could finish the selection based on the release location as in the
	// commented out code below, to allow text selections even in a terminal
	// that doesn't support mouse motion events. But when the mouse click is
	// within the scroll margin, that would cause a scroll and selection
	// even for a simple mouse click, which is not good.
	// if !h.DoubleClick && !h.TripleClick {
	// 	mx, my := e.Position()
	// 	h.Cursor.Loc = h.LocFromVisual(buffer.Loc{mx, my})
	// 	h.Cursor.SetSelectionEnd(h.Cursor.Loc)
	// }

	if h.Cursor.HasSelection() {
		h.Cursor.CopySelection(clipboard.PrimaryReg)
	}
	return true
}

// ScrollUpAction scrolls the view up
func (h *BufPane) ScrollUpAction() bool {
	h.ScrollUp(util.IntOpt(h.Buf.Settings["scrollspeed"]))
	return true
}

// ScrollDownAction scrolls the view down
func (h *BufPane) ScrollDownAction() bool {
	h.ScrollDown(util.IntOpt(h.Buf.Settings["scrollspeed"]))
	return true
}

// Center centers the view on the cursor
func (h *BufPane) Center() bool {
	v := h.GetView()
	v.StartLine = h.Scroll(h.SLocFromLoc(h.Cursor.Loc), -h.BufView().Height/2)
	h.SetView(v)
	h.ScrollAdjust()
	return true
}

// CursorToViewTop moves the cursor to the top of the view,
// offset by scrollmargin unless at the beginning or end of the file
func (h *BufPane) CursorToViewTop() bool {
	v := h.GetView()
	h.Buf.ClearCursors()
	scrollmargin := int(h.Buf.Settings["scrollmargin"].(float64))
	bStart := display.SLoc{0, 0}
	if v.StartLine == bStart {
		scrollmargin = 0
	}
	h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{
		SLoc:    h.Scroll(v.StartLine, scrollmargin),
		VisualX: 0,
	}))
	return true
}

// CursorToViewCenter moves the cursor to the center of the view
func (h *BufPane) CursorToViewCenter() bool {
	v := h.GetView()
	h.Buf.ClearCursors()
	h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{
		SLoc:    h.Scroll(v.StartLine, h.BufView().Height/2),
		VisualX: 0,
	}))
	return true
}

// CursorToViewBottom moves the cursor to the bottom of the view,
// offset by scrollmargin unless at the beginning or end of the file
func (h *BufPane) CursorToViewBottom() bool {
	v := h.GetView()
	h.Buf.ClearCursors()
	scrollmargin := int(h.Buf.Settings["scrollmargin"].(float64))
	bEnd := h.SLocFromLoc(h.Buf.End())
	lastLine := h.Scroll(v.StartLine, h.BufView().Height-1)
	if lastLine == bEnd {
		scrollmargin = 0
	}
	h.Cursor.GotoLoc(h.LocFromVLoc(display.VLoc{
		SLoc:    h.Scroll(lastLine, -scrollmargin),
		VisualX: 0,
	}))
	return true
}

// MoveCursorUp is not an action
func (h *BufPane) MoveCursorUp(n int) {
	if !h.Buf.Settings["softwrap"].(bool) {
		h.Cursor.UpN(n)
	} else {
		vloc := h.VLocFromLoc(h.Cursor.Loc)
		sloc := h.Scroll(vloc.SLoc, -n)
		if sloc == vloc.SLoc {
			// we are at the beginning of buffer
			h.Cursor.Loc = h.Buf.Start()
			h.Cursor.StoreVisualX()
		} else {
			vloc.SLoc = sloc
			vloc.VisualX = h.Cursor.LastWrappedVisualX
			h.Cursor.Loc = h.LocFromVLoc(vloc)
		}
	}
}

// MoveCursorDown is not an action
func (h *BufPane) MoveCursorDown(n int) {
	if !h.Buf.Settings["softwrap"].(bool) {
		h.Cursor.DownN(n)
	} else {
		vloc := h.VLocFromLoc(h.Cursor.Loc)
		sloc := h.Scroll(vloc.SLoc, n)
		if sloc == vloc.SLoc {
			// we are at the end of buffer
			h.Cursor.Loc = h.Buf.End()
			h.Cursor.StoreVisualX()
		} else {
			vloc.SLoc = sloc
			vloc.VisualX = h.Cursor.LastWrappedVisualX
			h.Cursor.Loc = h.LocFromVLoc(vloc)
		}
	}
}

// CursorUp moves the cursor up
func (h *BufPane) CursorUp() bool {
	h.Cursor.Deselect(true)
	h.MoveCursorUp(1)
	h.Relocate()
	return true
}

// CursorDown moves the cursor down
func (h *BufPane) CursorDown() bool {
	selectionEndNewline := h.Cursor.HasSelection() && h.Cursor.CurSelection[1].X == 0
	h.Cursor.Deselect(false)
	if selectionEndNewline {
		h.Cursor.Start()
	} else {
		h.MoveCursorDown(1)
	}
	h.Relocate()
	return true
}

// CursorLeft moves the cursor left
func (h *BufPane) CursorLeft() bool {
	if h.Cursor.HasSelection() {
		h.Cursor.Deselect(true)
	} else {
		tabstospaces := h.Buf.Settings["tabstospaces"].(bool)
		tabmovement := h.Buf.Settings["tabmovement"].(bool)
		if tabstospaces && tabmovement {
			tabsize := int(h.Buf.Settings["tabsize"].(float64))
			line := h.Buf.LineBytes(h.Cursor.Y)
			if h.Cursor.X-tabsize >= 0 && util.IsSpaces(line[h.Cursor.X-tabsize:h.Cursor.X]) && util.IsBytesWhitespace(line[0:h.Cursor.X-tabsize]) {
				for i := 0; i < tabsize; i++ {
					h.Cursor.Left()
				}
			} else {
				h.Cursor.Left()
			}
		} else {
			h.Cursor.Left()
		}
	}
	h.Relocate()
	return true
}

// CursorRight moves the cursor right
func (h *BufPane) CursorRight() bool {
	if h.Cursor.HasSelection() {
		h.Cursor.Deselect(false)
	} else {
		tabstospaces := h.Buf.Settings["tabstospaces"].(bool)
		tabmovement := h.Buf.Settings["tabmovement"].(bool)
		if tabstospaces && tabmovement {
			tabsize := int(h.Buf.Settings["tabsize"].(float64))
			line := h.Buf.LineBytes(h.Cursor.Y)
			if h.Cursor.X+tabsize < util.CharacterCount(line) && util.IsSpaces(line[h.Cursor.X:h.Cursor.X+tabsize]) && util.IsBytesWhitespace(line[0:h.Cursor.X]) {
				for i := 0; i < tabsize; i++ {
					h.Cursor.Right()
				}
			} else {
				h.Cursor.Right()
			}
		} else {
			h.Cursor.Right()
		}
	}

	h.Relocate()
	return true
}

// WordRight moves the cursor one word to the right
func (h *BufPane) WordRight() bool {
	h.Cursor.Deselect(false)
	h.Cursor.WordRight()
	h.Relocate()
	return true
}

// WordLeft moves the cursor one word to the left
func (h *BufPane) WordLeft() bool {
	h.Cursor.Deselect(true)
	h.Cursor.WordLeft()
	h.Relocate()
	return true
}

// SubWordRight moves the cursor one sub-word to the right
func (h *BufPane) SubWordRight() bool {
	h.Cursor.Deselect(false)
	h.Cursor.SubWordRight()
	h.Relocate()
	return true
}

// SubWordLeft moves the cursor one sub-word to the left
func (h *BufPane) SubWordLeft() bool {
	h.Cursor.Deselect(true)
	h.Cursor.SubWordLeft()
	h.Relocate()
	return true
}

// SelectUp selects up one line
func (h *BufPane) SelectUp() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.MoveCursorUp(1)
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectDown selects down one line
func (h *BufPane) SelectDown() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.MoveCursorDown(1)
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectLeft selects the character to the left of the cursor
func (h *BufPane) SelectLeft() bool {
	loc := h.Cursor.Loc
	count := h.Buf.End()
	if loc.GreaterThan(count) {
		loc = count
	}
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = loc
	}
	h.Cursor.Left()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectRight selects the character to the right of the cursor
func (h *BufPane) SelectRight() bool {
	loc := h.Cursor.Loc
	count := h.Buf.End()
	if loc.GreaterThan(count) {
		loc = count
	}
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = loc
	}
	h.Cursor.Right()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectWordRight selects the word to the right of the cursor
func (h *BufPane) SelectWordRight() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.Cursor.WordRight()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectWordLeft selects the word to the left of the cursor
func (h *BufPane) SelectWordLeft() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.Cursor.WordLeft()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectSubWordRight selects the sub-word to the right of the cursor
func (h *BufPane) SelectSubWordRight() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.Cursor.SubWordRight()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectSubWordLeft selects the sub-word to the left of the cursor
func (h *BufPane) SelectSubWordLeft() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.Cursor.SubWordLeft()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// StartOfText moves the cursor to the start of the text of the line
func (h *BufPane) StartOfText() bool {
	h.Cursor.Deselect(true)
	h.Cursor.StartOfText()
	h.Relocate()
	return true
}

// StartOfTextToggle toggles the cursor between the start of the text of the line
// and the start of the line
func (h *BufPane) StartOfTextToggle() bool {
	h.Cursor.Deselect(true)
	if h.Cursor.IsStartOfText() {
		h.Cursor.Start()
	} else {
		h.Cursor.StartOfText()
	}
	h.Relocate()
	return true
}

// StartOfLine moves the cursor to the start of the line
func (h *BufPane) StartOfLine() bool {
	h.Cursor.Deselect(true)
	h.Cursor.Start()
	h.Relocate()
	return true
}

// EndOfLine moves the cursor to the end of the line
func (h *BufPane) EndOfLine() bool {
	h.Cursor.Deselect(true)
	h.Cursor.End()
	h.Relocate()
	return true
}

// SelectLine selects the entire current line
func (h *BufPane) SelectLine() bool {
	h.Cursor.SelectLine()
	h.Relocate()
	return true
}

// SelectToStartOfText selects to the start of the text on the current line
func (h *BufPane) SelectToStartOfText() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.Cursor.StartOfText()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectToStartOfTextToggle toggles the selection between the start of the text
// on the current line and the start of the line
func (h *BufPane) SelectToStartOfTextToggle() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	if h.Cursor.IsStartOfText() {
		h.Cursor.Start()
	} else {
		h.Cursor.StartOfText()
	}
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectToStartOfLine selects to the start of the current line
func (h *BufPane) SelectToStartOfLine() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.Cursor.Start()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectToEndOfLine selects to the end of the current line
func (h *BufPane) SelectToEndOfLine() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.Cursor.End()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

func (h *BufPane) paragraphPrevious() {
	var line int
	// Skip to the first non-empty line
	for line = h.Cursor.Y; line > 0; line-- {
		if len(h.Buf.LineBytes(line)) != 0 {
			break
		}
	}
	// Find the first empty line
	for ; line > 0; line-- {
		if len(h.Buf.LineBytes(line)) == 0 {
			h.Cursor.X = 0
			h.Cursor.Y = line
			break
		}
	}
	// If no empty line was found, move the cursor to the start of the buffer
	if line == 0 {
		h.Cursor.Loc = h.Buf.Start()
	}
}

func (h *BufPane) paragraphNext() {
	var line int
	// Skip to the first non-empty line
	for line = h.Cursor.Y; line < h.Buf.LinesNum(); line++ {
		if len(h.Buf.LineBytes(line)) != 0 {
			break
		}
	}
	// Find the first empty line
	for ; line < h.Buf.LinesNum(); line++ {
		if len(h.Buf.LineBytes(line)) == 0 {
			h.Cursor.X = 0
			h.Cursor.Y = line
			break
		}
	}
	// If no empty line was found, move the cursor to the end of the buffer
	if line == h.Buf.LinesNum() {
		h.Cursor.Loc = h.Buf.End()
	}
}

// ParagraphPrevious moves the cursor to the first empty line that comes before
// the paragraph closest to the cursor, or beginning of the buffer if there
// isn't a paragraph
func (h *BufPane) ParagraphPrevious() bool {
	h.Cursor.Deselect(true)
	h.paragraphPrevious()
	h.Relocate()
	return true
}

// ParagraphNext moves the cursor to the first empty line that comes after the
// paragraph closest to the cursor, or end of the buffer if there isn't a
// paragraph
func (h *BufPane) ParagraphNext() bool {
	h.Cursor.Deselect(true)
	h.paragraphNext()
	h.Relocate()
	return true
}

// SelectToParagraphPrevious selects to the first empty line that comes before
// the paragraph closest to the cursor, or beginning of the buffer if there
// isn't a paragraph
func (h *BufPane) SelectToParagraphPrevious() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.paragraphPrevious()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// SelectToParagraphNext selects to the first empty line that comes after the
// paragraph closest to the cursor, or end of the buffer if there isn't a
// paragraph
func (h *BufPane) SelectToParagraphNext() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.paragraphNext()
	h.Cursor.SelectTo(h.Cursor.Loc)
	h.Relocate()
	return true
}

// Retab changes all tabs to spaces or all spaces to tabs depending
// on the user's settings
func (h *BufPane) Retab() bool {
	h.Buf.Retab()
	h.Relocate()
	return true
}

// CursorStart moves the cursor to the start of the buffer
func (h *BufPane) CursorStart() bool {
	h.Cursor.Deselect(true)
	h.Cursor.X = 0
	h.Cursor.Y = 0
	h.Cursor.StoreVisualX()
	h.Relocate()
	return true
}

// CursorEnd moves the cursor to the end of the buffer
func (h *BufPane) CursorEnd() bool {
	h.Cursor.Deselect(true)
	h.Cursor.Loc = h.Buf.End()
	h.Cursor.StoreVisualX()
	h.Relocate()
	return true
}

// SelectToStart selects the text from the cursor to the start of the buffer
func (h *BufPane) SelectToStart() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.CursorStart()
	h.Cursor.SelectTo(h.Buf.Start())
	h.Relocate()
	return true
}

// SelectToEnd selects the text from the cursor to the end of the buffer
func (h *BufPane) SelectToEnd() bool {
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.CursorEnd()
	h.Cursor.SelectTo(h.Buf.End())
	h.Relocate()
	return true
}

// InsertNewline inserts a newline plus possible some whitespace if autoindent is on
func (h *BufPane) InsertNewline() bool {
	// Insert a newline
	if h.Cursor.HasSelection() {
		h.Cursor.DeleteSelection()
		h.Cursor.ResetSelection()
	}

	ws := util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y))
	cx := h.Cursor.X
	h.Buf.Insert(h.Cursor.Loc, "\n")
	// h.Cursor.Right()

	if h.Buf.Settings["autoindent"].(bool) {
		if cx < len(ws) {
			ws = ws[0:cx]
		}
		h.Buf.Insert(h.Cursor.Loc, string(ws))
		// for i := 0; i < len(ws); i++ {
		// 	h.Cursor.Right()
		// }

		// Remove the whitespaces if keepautoindent setting is off
		if util.IsSpacesOrTabs(h.Buf.LineBytes(h.Cursor.Y-1)) && !h.Buf.Settings["keepautoindent"].(bool) {
			line := h.Buf.LineBytes(h.Cursor.Y - 1)
			h.Buf.Remove(buffer.Loc{X: 0, Y: h.Cursor.Y - 1}, buffer.Loc{X: util.CharacterCount(line), Y: h.Cursor.Y - 1})
		}
	}
	h.Cursor.StoreVisualX()
	h.Relocate()
	return true
}

// Backspace deletes the previous character
func (h *BufPane) Backspace() bool {
	if h.Cursor.HasSelection() {
		h.Cursor.DeleteSelection()
		h.Cursor.ResetSelection()
	} else if h.Cursor.Loc.GreaterThan(h.Buf.Start()) {
		// We have to do something a bit hacky here because we want to
		// delete the line by first moving left and then deleting backwards
		// but the undo redo would place the cursor in the wrong place
		// So instead we move left, save the position, move back, delete
		// and restore the position

		// If the user is using spaces instead of tabs and they are deleting
		// whitespace at the start of the line, we should delete as if it's a
		// tab (tabSize number of spaces)
		lineStart := util.SliceStart(h.Buf.LineBytes(h.Cursor.Y), h.Cursor.X)
		tabSize := int(h.Buf.Settings["tabsize"].(float64))
		if h.Buf.Settings["tabstospaces"].(bool) && util.IsSpaces(lineStart) && len(lineStart) != 0 && util.CharacterCount(lineStart)%tabSize == 0 {
			loc := h.Cursor.Loc
			h.Buf.Remove(loc.Move(-tabSize, h.Buf), loc)
		} else {
			loc := h.Cursor.Loc
			h.Buf.Remove(loc.Move(-1, h.Buf), loc)
		}
	}
	h.Cursor.StoreVisualX()
	h.Relocate()
	return true
}

// DeleteWordRight deletes the word to the right of the cursor
func (h *BufPane) DeleteWordRight() bool {
	h.SelectWordRight()
	if h.Cursor.HasSelection() {
		h.Cursor.DeleteSelection()
		h.Cursor.ResetSelection()
	}
	h.Relocate()
	return true
}

// DeleteWordLeft deletes the word to the left of the cursor
func (h *BufPane) DeleteWordLeft() bool {
	h.SelectWordLeft()
	if h.Cursor.HasSelection() {
		h.Cursor.DeleteSelection()
		h.Cursor.ResetSelection()
	}
	h.Relocate()
	return true
}

// DeleteSubWordRight deletes the sub-word to the right of the cursor
func (h *BufPane) DeleteSubWordRight() bool {
	h.SelectSubWordRight()
	if h.Cursor.HasSelection() {
		h.Cursor.DeleteSelection()
		h.Cursor.ResetSelection()
	}
	h.Relocate()
	return true
}

// DeleteSubWordLeft deletes the sub-word to the left of the cursor
func (h *BufPane) DeleteSubWordLeft() bool {
	h.SelectSubWordLeft()
	if h.Cursor.HasSelection() {
		h.Cursor.DeleteSelection()
		h.Cursor.ResetSelection()
	}
	h.Relocate()
	return true
}

// Delete deletes the next character
func (h *BufPane) Delete() bool {
	if h.Cursor.HasSelection() {
		h.Cursor.DeleteSelection()
		h.Cursor.ResetSelection()
	} else {
		loc := h.Cursor.Loc
		if loc.LessThan(h.Buf.End()) {
			h.Buf.Remove(loc, loc.Move(1, h.Buf))
		}
	}
	h.Relocate()
	return true
}

// IndentSelection indents the current selection
func (h *BufPane) IndentSelection() bool {
	if h.Cursor.HasSelection() {
		start := h.Cursor.CurSelection[0]
		end := h.Cursor.CurSelection[1]
		if end.Y < start.Y {
			start, end = end, start
			h.Cursor.SetSelectionStart(start)
			h.Cursor.SetSelectionEnd(end)
		}

		startY := start.Y
		endY := end.Move(-1, h.Buf).Y
		endX := end.Move(-1, h.Buf).X
		tabsize := int(h.Buf.Settings["tabsize"].(float64))
		indentsize := len(h.Buf.IndentString(tabsize))
		for y := startY; y <= endY; y++ {
			if len(h.Buf.LineBytes(y)) > 0 {
				h.Buf.Insert(buffer.Loc{X: 0, Y: y}, h.Buf.IndentString(tabsize))
				if y == startY && start.X > 0 {
					h.Cursor.SetSelectionStart(start.Move(indentsize, h.Buf))
				}
				if y == endY {
					h.Cursor.SetSelectionEnd(buffer.Loc{X: endX + indentsize + 1, Y: endY})
				}
			}
		}
		h.Buf.RelocateCursors()

		h.Relocate()
		return true
	}
	return false
}

// IndentLine moves the current line forward one indentation
func (h *BufPane) IndentLine() bool {
	if h.Cursor.HasSelection() {
		return false
	}

	tabsize := int(h.Buf.Settings["tabsize"].(float64))
	indentstr := h.Buf.IndentString(tabsize)
	h.Buf.Insert(buffer.Loc{X: 0, Y: h.Cursor.Y}, indentstr)
	h.Buf.RelocateCursors()
	h.Relocate()
	return true
}

// OutdentLine moves the current line back one indentation
func (h *BufPane) OutdentLine() bool {
	if h.Cursor.HasSelection() {
		return false
	}

	for x := 0; x < len(h.Buf.IndentString(util.IntOpt(h.Buf.Settings["tabsize"]))); x++ {
		if len(util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y))) == 0 {
			break
		}
		h.Buf.Remove(buffer.Loc{X: 0, Y: h.Cursor.Y}, buffer.Loc{X: 1, Y: h.Cursor.Y})
	}
	h.Buf.RelocateCursors()
	h.Relocate()
	return true
}

// OutdentSelection takes the current selection and moves it back one indent level
func (h *BufPane) OutdentSelection() bool {
	if h.Cursor.HasSelection() {
		start := h.Cursor.CurSelection[0]
		end := h.Cursor.CurSelection[1]
		if end.Y < start.Y {
			start, end = end, start
			h.Cursor.SetSelectionStart(start)
			h.Cursor.SetSelectionEnd(end)
		}

		startY := start.Y
		endY := end.Move(-1, h.Buf).Y
		for y := startY; y <= endY; y++ {
			for x := 0; x < len(h.Buf.IndentString(util.IntOpt(h.Buf.Settings["tabsize"]))); x++ {
				if len(util.GetLeadingWhitespace(h.Buf.LineBytes(y))) == 0 {
					break
				}
				h.Buf.Remove(buffer.Loc{X: 0, Y: y}, buffer.Loc{X: 1, Y: y})
			}
		}
		h.Buf.RelocateCursors()

		h.Relocate()
		return true
	}
	return false
}

// Autocomplete cycles the suggestions and performs autocompletion if there are suggestions
func (h *BufPane) Autocomplete() bool {
	b := h.Buf

	if h.Cursor.HasSelection() {
		return false
	}

	if b.HasSuggestions {
		b.CycleAutocomplete(true)
		return true
	}

	if h.Cursor.X == 0 {
		return false
	}
	r := h.Cursor.RuneUnder(h.Cursor.X)
	prev := h.Cursor.RuneUnder(h.Cursor.X - 1)
	if !util.IsAutocomplete(prev) || util.IsWordChar(r) {
		// don't autocomplete if cursor is within a word
		return false
	}

	return b.Autocomplete(buffer.BufferComplete)
}

// CycleAutocompleteBack cycles back in the autocomplete suggestion list
func (h *BufPane) CycleAutocompleteBack() bool {
	if h.Cursor.HasSelection() {
		return false
	}

	if h.Buf.HasSuggestions {
		h.Buf.CycleAutocomplete(false)
		return true
	}
	return false
}

// InsertTab inserts a tab or spaces
func (h *BufPane) InsertTab() bool {
	b := h.Buf
	indent := b.IndentString(util.IntOpt(b.Settings["tabsize"]))
	tabBytes := len(indent)
	bytesUntilIndent := tabBytes - (h.Cursor.GetVisualX(false) % tabBytes)
	b.Insert(h.Cursor.Loc, indent[:bytesUntilIndent])
	h.Relocate()
	return true
}

// SaveAll saves all open buffers
func (h *BufPane) SaveAll() bool {
	for _, b := range buffer.OpenBuffers {
		b.Save()
	}
	return true
}

// SaveCB performs a save and does a callback at the very end (after all prompts have been resolved)
func (h *BufPane) SaveCB(action string, callback func()) bool {
	// If this is an empty buffer, ask for a filename
	if h.Buf.Path == "" {
		h.SaveAsCB(action, callback)
	} else {
		noPrompt := h.saveBufToFile(h.Buf.Path, action, callback)
		if noPrompt {
			return true
		}
	}
	return false
}

// Save the buffer to disk
func (h *BufPane) Save() bool {
	return h.SaveCB("Save", nil)
}

// SaveAsCB performs a save as and does a callback at the very end (after all prompts have been resolved)
// The callback is only called if the save was successful
func (h *BufPane) SaveAsCB(action string, callback func()) bool {
	InfoBar.Prompt("Filename: ", "", "Save", nil, func(resp string, canceled bool) {
		if !canceled {
			// the filename might or might not be quoted, so unquote first then join the strings.
			args, err := shellquote.Split(resp)
			if err != nil {
				InfoBar.Error("Error parsing arguments: ", err)
				return
			}
			if len(args) == 0 {
				InfoBar.Error("No filename given")
				return
			}
			filename := strings.Join(args, " ")
			fileinfo, err := os.Stat(filename)
			if err != nil {
				if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrPermission) {
					noPrompt := h.saveBufToFile(filename, action, callback)
					if noPrompt {
						h.completeAction(action)
						return
					}
				} else {
					InfoBar.Error(err)
					return
				}
			} else {
				InfoBar.YNPrompt(
					fmt.Sprintf("The file %s already exists in the directory, would you like to overwrite? Y/n", fileinfo.Name()),
					func(yes, canceled bool) {
						if yes && !canceled {
							noPrompt := h.saveBufToFile(filename, action, callback)
							if noPrompt {
								h.completeAction(action)
							}
						}
					},
				)
			}
		}
	})
	return false
}

// SaveAs saves the buffer to disk with the given name
func (h *BufPane) SaveAs() bool {
	return h.SaveAsCB("SaveAs", nil)
}

// This function saves the buffer to `filename` and changes the buffer's path and name
// to `filename` if the save is successful
// The callback is only called if the save was successful
func (h *BufPane) saveBufToFile(filename string, action string, callback func()) bool {
	err := h.Buf.SaveAs(filename)
	if err != nil {
		if errors.Is(err, fs.ErrPermission) {
			if runtime.GOOS == "windows" {
				InfoBar.Error("Permission denied. Save with sudo not supported on Windows")
				return true
			}

			saveWithSudo := func() {
				err = h.Buf.SaveAsWithSudo(filename)
				if err != nil {
					InfoBar.Error(err)
				} else {
					InfoBar.Message("Saved " + filename)
					if callback != nil {
						callback()
					}
				}
			}
			if h.Buf.Settings["autosu"].(bool) {
				saveWithSudo()
			} else {
				InfoBar.YNPrompt(
					fmt.Sprintf("Permission denied. Do you want to save this file using %s? (y,n)", config.GlobalSettings["sucmd"].(string)),
					func(yes, canceled bool) {
						if yes && !canceled {
							saveWithSudo()
							h.completeAction(action)
						}
					},
				)
				return false
			}
		} else {
			InfoBar.Error(err)
		}
	} else {
		InfoBar.Message("Saved " + filename)
		if callback != nil {
			callback()
		}
	}
	return true
}

// Find opens a prompt and searches forward for the input
func (h *BufPane) Find() bool {
	return h.find(true)
}

// FindLiteral is the same as Find() but does not support regular expressions
func (h *BufPane) FindLiteral() bool {
	return h.find(false)
}

// Search searches for a given string/regex in the buffer and selects the next
// match if a match is found
// This function behaves the same way as Find and FindLiteral actions:
// it affects the buffer's LastSearch and LastSearchRegex (saved searches)
// for use with FindNext and FindPrevious, and turns HighlightSearch on or off
// according to hlsearch setting
func (h *BufPane) Search(str string, useRegex bool, searchDown bool) error {
	match, found, err := h.Buf.FindNext(str, h.Buf.Start(), h.Buf.End(), h.Cursor.Loc, searchDown, useRegex)
	if err != nil {
		return err
	}
	if found {
		h.Cursor.SetSelectionStart(match[0])
		h.Cursor.SetSelectionEnd(match[1])
		h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0]
		h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1]
		h.GotoLoc(h.Cursor.CurSelection[1])
		h.Buf.LastSearch = str
		h.Buf.LastSearchRegex = useRegex
		h.Buf.HighlightSearch = h.Buf.Settings["hlsearch"].(bool)
	} else {
		h.Cursor.ResetSelection()
	}
	return nil
}

func (h *BufPane) find(useRegex bool) bool {
	h.searchOrig = h.Cursor.Loc
	prompt := "Find: "
	if useRegex {
		prompt = "Find (regex): "
	}
	var eventCallback func(resp string)
	if h.Buf.Settings["incsearch"].(bool) {
		eventCallback = func(resp string) {
			match, found, _ := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, useRegex)
			if found {
				h.Cursor.SetSelectionStart(match[0])
				h.Cursor.SetSelectionEnd(match[1])
				h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0]
				h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1]
				h.GotoLoc(match[1])
			} else {
				h.GotoLoc(h.searchOrig)
				h.Cursor.ResetSelection()
			}
		}
	}
	findCallback := func(resp string, canceled bool) {
		// Finished callback
		if !canceled {
			match, found, err := h.Buf.FindNext(resp, h.Buf.Start(), h.Buf.End(), h.searchOrig, true, useRegex)
			if err != nil {
				InfoBar.Error(err)
			} else if found {
				h.Cursor.SetSelectionStart(match[0])
				h.Cursor.SetSelectionEnd(match[1])
				h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0]
				h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1]
				h.GotoLoc(h.Cursor.CurSelection[1])
				h.Buf.LastSearch = resp
				h.Buf.LastSearchRegex = useRegex
				h.Buf.HighlightSearch = h.Buf.Settings["hlsearch"].(bool)
			} else {
				h.Cursor.ResetSelection()
				InfoBar.Message("No matches found")
			}
		} else {
			h.Cursor.ResetSelection()
		}
	}
	pattern := string(h.Cursor.GetSelection())
	if useRegex && pattern != "" {
		pattern = regexp.QuoteMeta(pattern)
	}
	if eventCallback != nil && pattern != "" {
		eventCallback(pattern)
	}
	InfoBar.Prompt(prompt, pattern, "Find", eventCallback, findCallback)
	if pattern != "" {
		InfoBar.SelectAll()
	}
	return true
}

// ToggleHighlightSearch toggles highlighting all instances of the last used search term
func (h *BufPane) ToggleHighlightSearch() bool {
	h.Buf.HighlightSearch = !h.Buf.HighlightSearch
	return true
}

// UnhighlightSearch unhighlights all instances of the last used search term
func (h *BufPane) UnhighlightSearch() bool {
	if !h.Buf.HighlightSearch {
		return false
	}
	h.Buf.HighlightSearch = false
	return true
}

// ResetSearch resets the last used search term
func (h *BufPane) ResetSearch() bool {
	if h.Buf.LastSearch != "" {
		h.Buf.LastSearch = ""
		return true
	}
	return false
}

// FindNext searches forwards for the last used search term
func (h *BufPane) FindNext() bool {
	if h.Buf.LastSearch == "" {
		return false
	}
	// If the cursor is at the start of a selection and we search we want
	// to search from the end of the selection in the case that
	// the selection is a search result in which case we wouldn't move at
	// at all which would be bad
	searchLoc := h.Cursor.Loc
	if h.Cursor.HasSelection() {
		searchLoc = h.Cursor.CurSelection[1]
	}
	match, found, err := h.Buf.FindNext(h.Buf.LastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, true, h.Buf.LastSearchRegex)
	if err != nil {
		InfoBar.Error(err)
	} else if found && searchLoc == match[0] && match[0] == match[1] {
		// skip empty match at present cursor location
		if searchLoc == h.Buf.End() {
			searchLoc = h.Buf.Start()
		} else {
			searchLoc = searchLoc.Move(1, h.Buf)
		}
		match, found, _ = h.Buf.FindNext(h.Buf.LastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, true, h.Buf.LastSearchRegex)
	}
	if found {
		h.Cursor.SetSelectionStart(match[0])
		h.Cursor.SetSelectionEnd(match[1])
		h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0]
		h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1]
		h.GotoLoc(h.Cursor.CurSelection[1])
	} else {
		h.Cursor.ResetSelection()
	}
	return true
}

// FindPrevious searches backwards for the last used search term
func (h *BufPane) FindPrevious() bool {
	if h.Buf.LastSearch == "" {
		return false
	}
	// If the cursor is at the end of a selection and we search we want
	// to search from the beginning of the selection in the case that
	// the selection is a search result in which case we wouldn't move at
	// at all which would be bad
	searchLoc := h.Cursor.Loc
	if h.Cursor.HasSelection() {
		searchLoc = h.Cursor.CurSelection[0]
	}
	match, found, err := h.Buf.FindNext(h.Buf.LastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, false, h.Buf.LastSearchRegex)
	if err != nil {
		InfoBar.Error(err)
	} else if found && searchLoc == match[0] && match[0] == match[1] {
		// skip empty match at present cursor location
		if searchLoc == h.Buf.Start() {
			searchLoc = h.Buf.End()
		} else {
			searchLoc = searchLoc.Move(-1, h.Buf)
		}
		match, found, _ = h.Buf.FindNext(h.Buf.LastSearch, h.Buf.Start(), h.Buf.End(), searchLoc, false, h.Buf.LastSearchRegex)
	}
	if found {
		h.Cursor.SetSelectionStart(match[0])
		h.Cursor.SetSelectionEnd(match[1])
		h.Cursor.OrigSelection[0] = h.Cursor.CurSelection[0]
		h.Cursor.OrigSelection[1] = h.Cursor.CurSelection[1]
		h.GotoLoc(h.Cursor.CurSelection[1])
	} else {
		h.Cursor.ResetSelection()
	}
	return true
}

// DiffNext searches forward until the beginning of the next block of diffs
func (h *BufPane) DiffNext() bool {
	cur := h.Cursor.Loc.Y
	dl, err := h.Buf.FindNextDiffLine(cur, true)
	if err != nil {
		return false
	}
	h.GotoLoc(buffer.Loc{0, dl})
	return true
}

// DiffPrevious searches forward until the end of the previous block of diffs
func (h *BufPane) DiffPrevious() bool {
	cur := h.Cursor.Loc.Y
	dl, err := h.Buf.FindNextDiffLine(cur, false)
	if err != nil {
		return false
	}
	h.GotoLoc(buffer.Loc{0, dl})
	return true
}

// Undo undoes the last action
func (h *BufPane) Undo() bool {
	if !h.Buf.Undo() {
		return false
	}
	InfoBar.Message("Undid action")
	h.Relocate()
	return true
}

// Redo redoes the last action
func (h *BufPane) Redo() bool {
	if !h.Buf.Redo() {
		return false
	}
	InfoBar.Message("Redid action")
	h.Relocate()
	return true
}

func (h *BufPane) selectLines() int {
	if h.Cursor.HasSelection() {
		start := h.Cursor.CurSelection[0]
		end := h.Cursor.CurSelection[1]
		if start.GreaterThan(end) {
			start, end = end, start
		}
		if end.X == 0 {
			end = end.Move(-1, h.Buf)
		}

		h.Cursor.Deselect(true)
		h.Cursor.SetSelectionStart(buffer.Loc{0, start.Y})
		h.Cursor.SetSelectionEnd(buffer.Loc{0, end.Y + 1})
	} else {
		h.Cursor.SelectLine()
	}

	nlines := h.Cursor.CurSelection[1].Y - h.Cursor.CurSelection[0].Y
	if nlines == 0 && h.Cursor.HasSelection() {
		// selected last line and it is not empty
		nlines++
	}
	return nlines
}

// Copy the selection to the system clipboard
func (h *BufPane) Copy() bool {
	if !h.Cursor.HasSelection() {
		return false
	}
	h.Cursor.CopySelection(clipboard.ClipboardReg)
	h.freshClip = false
	InfoBar.Message("Copied selection")
	h.Relocate()
	return true
}

// CopyLine copies the current line to the clipboard. If there is a selection,
// CopyLine copies all the lines that are (fully or partially) in the selection.
func (h *BufPane) CopyLine() bool {
	origLoc := h.Cursor.Loc
	origLastVisualX := h.Cursor.LastVisualX
	origLastWrappedVisualX := h.Cursor.LastWrappedVisualX
	origSelection := h.Cursor.CurSelection

	nlines := h.selectLines()
	if nlines == 0 {
		return false
	}
	h.Cursor.CopySelection(clipboard.ClipboardReg)
	h.freshClip = false
	if nlines > 1 {
		InfoBar.Message(fmt.Sprintf("Copied %d lines", nlines))
	} else {
		InfoBar.Message("Copied line")
	}

	h.Cursor.Loc = origLoc
	h.Cursor.LastVisualX = origLastVisualX
	h.Cursor.LastWrappedVisualX = origLastWrappedVisualX
	h.Cursor.CurSelection = origSelection
	h.Relocate()
	return true
}

// Cut the selection to the system clipboard
func (h *BufPane) Cut() bool {
	if !h.Cursor.HasSelection() {
		return false
	}
	h.Cursor.CopySelection(clipboard.ClipboardReg)
	h.Cursor.DeleteSelection()
	h.Cursor.ResetSelection()
	h.freshClip = false
	InfoBar.Message("Cut selection")

	h.Relocate()
	return true
}

// CutLine cuts the current line to the clipboard. If there is a selection,
// CutLine cuts all the lines that are (fully or partially) in the selection.
func (h *BufPane) CutLine() bool {
	nlines := h.selectLines()
	if nlines == 0 {
		return false
	}
	totalLines := nlines
	if h.freshClip {
		if clip, err := clipboard.Read(clipboard.ClipboardReg); err != nil {
			InfoBar.Error(err)
			return false
		} else {
			clipboard.WriteMulti(clip+string(h.Cursor.GetSelection()), clipboard.ClipboardReg, h.Cursor.Num, h.Buf.NumCursors())
			totalLines = strings.Count(clip, "\n") + nlines
		}
	} else {
		h.Cursor.CopySelection(clipboard.ClipboardReg)
	}
	h.freshClip = true
	h.Cursor.DeleteSelection()
	h.Cursor.ResetSelection()
	h.Cursor.StoreVisualX()
	if totalLines > 1 {
		InfoBar.Message(fmt.Sprintf("Cut %d lines", totalLines))
	} else {
		InfoBar.Message("Cut line")
	}
	h.Relocate()
	return true
}

// Duplicate the selection
func (h *BufPane) Duplicate() bool {
	if !h.Cursor.HasSelection() {
		return false
	}
	h.Buf.Insert(h.Cursor.CurSelection[1], string(h.Cursor.GetSelection()))
	InfoBar.Message("Duplicated selection")
	h.Relocate()
	return true
}

// DuplicateLine duplicates the current line. If there is a selection, DuplicateLine
// duplicates all the lines that are (fully or partially) in the selection.
func (h *BufPane) DuplicateLine() bool {
	if h.Cursor.HasSelection() {
		origLoc := h.Cursor.Loc
		origLastVisualX := h.Cursor.LastVisualX
		origLastWrappedVisualX := h.Cursor.LastWrappedVisualX
		origSelection := h.Cursor.CurSelection

		start := h.Cursor.CurSelection[0]
		end := h.Cursor.CurSelection[1]
		if start.GreaterThan(end) {
			start, end = end, start
		}
		if end.X == 0 {
			end = end.Move(-1, h.Buf)
		}

		h.Cursor.Deselect(true)
		h.Cursor.Loc = end
		h.Cursor.End()
		for y := start.Y; y <= end.Y; y++ {
			h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(y)))
		}

		h.Cursor.Loc = origLoc
		h.Cursor.LastVisualX = origLastVisualX
		h.Cursor.LastWrappedVisualX = origLastWrappedVisualX
		h.Cursor.CurSelection = origSelection

		if start.Y < end.Y {
			InfoBar.Message(fmt.Sprintf("Duplicated %d lines", end.Y-start.Y+1))
		} else {
			InfoBar.Message("Duplicated line")
		}
	} else {
		h.Cursor.End()
		h.Buf.Insert(h.Cursor.Loc, "\n"+string(h.Buf.LineBytes(h.Cursor.Y)))
		InfoBar.Message("Duplicated line")
	}
	h.Relocate()
	return true
}

// DeleteLine deletes the current line. If there is a selection, DeleteLine
// deletes all the lines that are (fully or partially) in the selection.
func (h *BufPane) DeleteLine() bool {
	nlines := h.selectLines()
	if nlines == 0 {
		return false
	}
	h.Cursor.DeleteSelection()
	h.Cursor.ResetSelection()
	h.Cursor.StoreVisualX()
	if nlines > 1 {
		InfoBar.Message(fmt.Sprintf("Deleted %d lines", nlines))
	} else {
		InfoBar.Message("Deleted line")
	}
	h.Relocate()
	return true
}

// MoveLinesUp moves up the current line or selected lines if any
func (h *BufPane) MoveLinesUp() bool {
	if h.Cursor.HasSelection() {
		if h.Cursor.CurSelection[0].Y == 0 {
			InfoBar.Message("Cannot move further up")
			return false
		}
		start := h.Cursor.CurSelection[0].Y
		end := h.Cursor.CurSelection[1].Y
		sel := 1
		if start > end {
			end, start = start, end
			sel = 0
		}

		compensate := false
		if h.Cursor.CurSelection[sel].X != 0 {
			end++
		} else {
			compensate = true
		}

		h.Buf.MoveLinesUp(
			start,
			end,
		)
		if compensate {
			h.Cursor.CurSelection[sel].Y -= 1
		}
	} else {
		if h.Cursor.Loc.Y == 0 {
			InfoBar.Message("Cannot move further up")
			return false
		}
		h.Buf.MoveLinesUp(
			h.Cursor.Loc.Y,
			h.Cursor.Loc.Y+1,
		)
	}

	h.Relocate()
	return true
}

// MoveLinesDown moves down the current line or selected lines if any
func (h *BufPane) MoveLinesDown() bool {
	if h.Cursor.HasSelection() {
		if h.Cursor.CurSelection[1].Y >= h.Buf.LinesNum() {
			InfoBar.Message("Cannot move further down")
			return false
		}
		start := h.Cursor.CurSelection[0].Y
		end := h.Cursor.CurSelection[1].Y
		sel := 1
		if start > end {
			end, start = start, end
			sel = 0
		}

		if h.Cursor.CurSelection[sel].X != 0 {
			end++
		}

		h.Buf.MoveLinesDown(
			start,
			end,
		)
	} else {
		if h.Cursor.Loc.Y >= h.Buf.LinesNum()-1 {
			InfoBar.Message("Cannot move further down")
			return false
		}
		h.Buf.MoveLinesDown(
			h.Cursor.Loc.Y,
			h.Cursor.Loc.Y+1,
		)
	}

	h.Relocate()
	return true
}

// Paste whatever is in the system clipboard into the buffer
// Delete and paste if the user has a selection
func (h *BufPane) Paste() bool {
	clip, err := clipboard.ReadMulti(clipboard.ClipboardReg, h.Cursor.Num, h.Buf.NumCursors())
	if err != nil {
		InfoBar.Error(err)
	} else {
		h.paste(clip)
	}
	h.Relocate()
	return true
}

// PastePrimary pastes from the primary clipboard (only use on linux)
func (h *BufPane) PastePrimary() bool {
	clip, err := clipboard.ReadMulti(clipboard.PrimaryReg, h.Cursor.Num, h.Buf.NumCursors())
	if err != nil {
		InfoBar.Error(err)
	} else {
		h.paste(clip)
	}
	h.Relocate()
	return true
}

func (h *BufPane) paste(clip string) {
	if h.Buf.Settings["smartpaste"].(bool) {
		if h.Cursor.X > 0 {
			leadingPasteWS := string(util.GetLeadingWhitespace([]byte(clip)))
			if leadingPasteWS != " " && strings.Contains(clip, "\n"+leadingPasteWS) {
				leadingWS := string(util.GetLeadingWhitespace(h.Buf.LineBytes(h.Cursor.Y)))
				clip = strings.TrimPrefix(clip, leadingPasteWS)
				clip = strings.ReplaceAll(clip, "\n"+leadingPasteWS, "\n"+leadingWS)
			}
		}
	}

	if h.Cursor.HasSelection() {
		h.Cursor.DeleteSelection()
		h.Cursor.ResetSelection()
	}

	h.Buf.Insert(h.Cursor.Loc, clip)
	// h.Cursor.Loc = h.Cursor.Loc.Move(Count(clip), h.Buf)
	h.freshClip = false
	InfoBar.Message("Pasted clipboard")
}

// JumpToMatchingBrace moves the cursor to the matching brace if it is
// currently on a brace
func (h *BufPane) JumpToMatchingBrace() bool {
	matchingBrace, left, found := h.Buf.FindMatchingBrace(h.Cursor.Loc)
	if found {
		if h.Buf.Settings["matchbraceleft"].(bool) {
			if left {
				h.Cursor.GotoLoc(matchingBrace)
			} else {
				h.Cursor.GotoLoc(matchingBrace.Move(1, h.Buf))
			}
		} else {
			h.Cursor.GotoLoc(matchingBrace)
		}
		h.Relocate()
		return true
	}
	return false
}

// SelectAll selects the entire buffer
func (h *BufPane) SelectAll() bool {
	h.Cursor.SetSelectionStart(h.Buf.Start())
	h.Cursor.SetSelectionEnd(h.Buf.End())
	// Put the cursor at the beginning
	h.Cursor.X = 0
	h.Cursor.Y = 0
	h.Relocate()
	return true
}

// OpenFile opens a new file in the buffer
func (h *BufPane) OpenFile() bool {
	InfoBar.Prompt("> ", "open ", "Open", nil, func(resp string, canceled bool) {
		if !canceled {
			h.HandleCommand(resp)
		}
	})
	return true
}

// JumpLine asks the user to enter a line number to jump to
func (h *BufPane) JumpLine() bool {
	InfoBar.Prompt("> ", "goto ", "Command", nil, func(resp string, canceled bool) {
		if !canceled {
			h.HandleCommand(resp)
		}
	})
	return true
}

// Start moves the viewport to the start of the buffer
func (h *BufPane) Start() bool {
	v := h.GetView()
	v.StartLine = display.SLoc{0, 0}
	h.SetView(v)
	return true
}

// End moves the viewport to the end of the buffer
func (h *BufPane) End() bool {
	v := h.GetView()
	v.StartLine = h.Scroll(h.SLocFromLoc(h.Buf.End()), -h.BufView().Height+1)
	h.SetView(v)
	return true
}

// PageUp scrolls the view up a page
func (h *BufPane) PageUp() bool {
	pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64))
	h.ScrollUp(h.BufView().Height - pageOverlap)
	return true
}

// PageDown scrolls the view down a page
func (h *BufPane) PageDown() bool {
	pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64))
	h.ScrollDown(h.BufView().Height - pageOverlap)
	h.ScrollAdjust()
	return true
}

// SelectPageUp selects up one page
func (h *BufPane) SelectPageUp() bool {
	pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64))
	scrollAmount := h.BufView().Height - pageOverlap
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.MoveCursorUp(scrollAmount)
	h.Cursor.SelectTo(h.Cursor.Loc)
	if h.Cursor.Num == 0 {
		h.ScrollUp(scrollAmount)
	}
	h.Relocate()
	return true
}

// SelectPageDown selects down one page
func (h *BufPane) SelectPageDown() bool {
	pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64))
	scrollAmount := h.BufView().Height - pageOverlap
	if !h.Cursor.HasSelection() {
		h.Cursor.OrigSelection[0] = h.Cursor.Loc
	}
	h.MoveCursorDown(scrollAmount)
	h.Cursor.SelectTo(h.Cursor.Loc)
	if h.Cursor.Num == 0 && !h.ScrollReachedEnd() {
		h.ScrollDown(scrollAmount)
		h.ScrollAdjust()
	}
	h.Relocate()
	return true
}

// CursorPageUp places the cursor a page up,
// moving the view to keep cursor at the same relative position in the view
func (h *BufPane) CursorPageUp() bool {
	h.Cursor.Deselect(true)
	pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64))
	scrollAmount := h.BufView().Height - pageOverlap
	h.MoveCursorUp(scrollAmount)
	if h.Cursor.Num == 0 {
		h.ScrollUp(scrollAmount)
	}
	h.Relocate()
	return true
}

// CursorPageDown places the cursor a page down,
// moving the view to keep cursor at the same relative position in the view
func (h *BufPane) CursorPageDown() bool {
	selectionEndNewline := h.Cursor.HasSelection() && h.Cursor.CurSelection[1].X == 0
	h.Cursor.Deselect(false)
	pageOverlap := int(h.Buf.Settings["pageoverlap"].(float64))
	scrollAmount := h.BufView().Height - pageOverlap
	if selectionEndNewline {
		scrollAmount--
	}
	h.MoveCursorDown(scrollAmount)
	if h.Cursor.Num == 0 && !h.ScrollReachedEnd() {
		h.ScrollDown(scrollAmount)
		h.ScrollAdjust()
	}
	if selectionEndNewline {
		h.Cursor.Start()
	}
	h.Relocate()
	return true
}

// HalfPageUp scroll
Download .txt
gitextract_jznqtz0z/

├── .editorconfig
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 01-bug.yml
│   │   ├── 02-feature.yml
│   │   └── config.yml
│   └── workflows/
│       ├── nightly.yaml
│       ├── release.yaml
│       └── test.yaml
├── .gitignore
├── LICENSE
├── LICENSE-THIRD-PARTY
├── Makefile
├── README.md
├── assets/
│   └── packaging/
│       ├── deb/
│       │   ├── micro.postinst
│       │   └── micro.prerm
│       ├── micro.1
│       └── micro.desktop
├── cmd/
│   └── micro/
│       ├── clean.go
│       ├── debug.go
│       ├── initlua.go
│       ├── micro.go
│       └── micro_test.go
├── data/
│   ├── io.github.zyedidia.micro.metainfo.xml
│   └── micro.json
├── go.mod
├── go.sum
├── internal/
│   ├── action/
│   │   ├── actions.go
│   │   ├── actions_other.go
│   │   ├── actions_posix.go
│   │   ├── bindings.go
│   │   ├── bufpane.go
│   │   ├── command.go
│   │   ├── defaults.go
│   │   ├── defaults_darwin.go
│   │   ├── defaults_other.go
│   │   ├── events.go
│   │   ├── globals.go
│   │   ├── infocomplete.go
│   │   ├── infopane.go
│   │   ├── keytree.go
│   │   ├── pane.go
│   │   ├── rawpane.go
│   │   ├── tab.go
│   │   ├── terminal_supported.go
│   │   ├── terminal_unsupported.go
│   │   └── termpane.go
│   ├── buffer/
│   │   ├── autocomplete.go
│   │   ├── backup.go
│   │   ├── buffer.go
│   │   ├── buffer_generated_test.go
│   │   ├── buffer_test.go
│   │   ├── cursor.go
│   │   ├── eventhandler.go
│   │   ├── line_array.go
│   │   ├── line_array_test.go
│   │   ├── loc.go
│   │   ├── message.go
│   │   ├── save.go
│   │   ├── search.go
│   │   ├── serialize.go
│   │   ├── settings.go
│   │   ├── stack.go
│   │   └── stack_test.go
│   ├── clipboard/
│   │   ├── clipboard.go
│   │   ├── internal.go
│   │   ├── multi.go
│   │   └── terminal.go
│   ├── config/
│   │   ├── autosave.go
│   │   ├── colorscheme.go
│   │   ├── colorscheme_test.go
│   │   ├── config.go
│   │   ├── globals.go
│   │   ├── plugin.go
│   │   ├── plugin_installer.go
│   │   ├── plugin_installer_test.go
│   │   ├── plugin_manager.go
│   │   ├── rtfiles.go
│   │   ├── rtfiles_test.go
│   │   └── settings.go
│   ├── display/
│   │   ├── bufwindow.go
│   │   ├── infowindow.go
│   │   ├── softwrap.go
│   │   ├── statusline.go
│   │   ├── tabwindow.go
│   │   ├── termwindow.go
│   │   ├── uiwindow.go
│   │   └── window.go
│   ├── info/
│   │   ├── gutter.go
│   │   ├── history.go
│   │   └── infobuffer.go
│   ├── lua/
│   │   └── lua.go
│   ├── screen/
│   │   ├── message.go
│   │   └── screen.go
│   ├── shell/
│   │   ├── job.go
│   │   ├── shell.go
│   │   └── terminal.go
│   ├── util/
│   │   ├── lua.go
│   │   ├── profile.go
│   │   ├── unicode.go
│   │   ├── util.go
│   │   └── util_test.go
│   └── views/
│       ├── splits.go
│       └── splits_test.go
├── pkg/
│   └── highlight/
│       ├── highlighter.go
│       ├── parser.go
│       └── unicode.go
├── runtime/
│   ├── README.md
│   ├── colorschemes/
│   │   ├── atom-dark.micro
│   │   ├── bubblegum.micro
│   │   ├── cmc-16.micro
│   │   ├── cmc-tc.micro
│   │   ├── darcula.micro
│   │   ├── default.micro
│   │   ├── dracula-tc.micro
│   │   ├── dukedark-tc.micro
│   │   ├── dukelight-tc.micro
│   │   ├── dukeubuntu-tc.micro
│   │   ├── geany.micro
│   │   ├── gotham.micro
│   │   ├── gruvbox-tc.micro
│   │   ├── gruvbox.micro
│   │   ├── material-tc.micro
│   │   ├── monokai-dark.micro
│   │   ├── monokai.micro
│   │   ├── one-dark.micro
│   │   ├── railscast.micro
│   │   ├── simple.micro
│   │   ├── solarized-tc.micro
│   │   ├── solarized.micro
│   │   ├── sunny-day.micro
│   │   ├── twilight.micro
│   │   └── zenburn.micro
│   ├── help/
│   │   ├── colors.md
│   │   ├── commands.md
│   │   ├── copypaste.md
│   │   ├── defaultkeys.md
│   │   ├── help.md
│   │   ├── keybindings.md
│   │   ├── options.md
│   │   ├── plugins.md
│   │   └── tutorial.md
│   ├── plugins/
│   │   ├── autoclose/
│   │   │   └── autoclose.lua
│   │   ├── comment/
│   │   │   ├── comment.lua
│   │   │   └── help/
│   │   │       └── comment.md
│   │   ├── diff/
│   │   │   └── diff.lua
│   │   ├── ftoptions/
│   │   │   └── ftoptions.lua
│   │   ├── linter/
│   │   │   ├── help/
│   │   │   │   └── linter.md
│   │   │   └── linter.lua
│   │   ├── literate/
│   │   │   ├── README.md
│   │   │   └── literate.lua
│   │   └── status/
│   │       ├── help/
│   │       │   └── status.md
│   │       └── status.lua
│   ├── runtime.go
│   ├── runtime_test.go
│   └── syntax/
│       ├── LICENSE
│       ├── PowerShell.yaml
│       ├── README.md
│       ├── ada.yaml
│       ├── apacheconf.yaml
│       ├── arduino.yaml
│       ├── asciidoc.yaml
│       ├── asm.yaml
│       ├── ats.yaml
│       ├── awk.yaml
│       ├── b.yaml
│       ├── bat.yaml
│       ├── c.yaml
│       ├── caddyfile.yaml
│       ├── cake.yaml
│       ├── clojure.yaml
│       ├── cmake.yaml
│       ├── coffeescript.yaml
│       ├── colortest.yaml
│       ├── conky.yaml
│       ├── cpp.yaml
│       ├── crontab.yaml
│       ├── crystal.yaml
│       ├── csharp.yaml
│       ├── css.yaml
│       ├── csx.yaml
│       ├── cuda.yaml
│       ├── cython.yaml
│       ├── d.yaml
│       ├── dart.yaml
│       ├── default.yaml
│       ├── dockerfile.yaml
│       ├── dot.yaml
│       ├── elixir.yaml
│       ├── elm.yaml
│       ├── erb.yaml
│       ├── erlang.yaml
│       ├── fish.yaml
│       ├── forth.yaml
│       ├── fortran.yaml
│       ├── freebsd-kernel.yaml
│       ├── fsharp.yaml
│       ├── gdscript.yaml
│       ├── gemini.yaml
│       ├── gentoo-ebuild.yaml
│       ├── gentoo-etc-portage.yaml
│       ├── git-commit.yaml
│       ├── git-config.yaml
│       ├── git-rebase-todo.yaml
│       ├── glsl.yaml
│       ├── gnuplot.yaml
│       ├── go.yaml
│       ├── godoc.yaml
│       ├── golo.yaml
│       ├── gomod.yaml
│       ├── graphql.yaml
│       ├── groff.yaml
│       ├── groovy.yaml
│       ├── haml.yaml
│       ├── hare.yaml
│       ├── haskell.yaml
│       ├── hc.yaml
│       ├── html.yaml
│       ├── html4.yaml
│       ├── html5.yaml
│       ├── ini.yaml
│       ├── inputrc.yaml
│       ├── java.yaml
│       ├── javascript.yaml
│       ├── jinja2.yaml
│       ├── json.yaml
│       ├── jsonnet.yaml
│       ├── julia.yaml
│       ├── justfile.yaml
│       ├── keymap.yaml
│       ├── kickstart.yaml
│       ├── kotlin.yaml
│       ├── kvlang.yaml
│       ├── ledger.yaml
│       ├── lfe.yaml
│       ├── lilypond.yaml
│       ├── lisp.yaml
│       ├── log.yaml
│       ├── lua.yaml
│       ├── mail.yaml
│       ├── make_headers.go
│       ├── makefile.yaml
│       ├── man.yaml
│       ├── markdown.yaml
│       ├── mc.yaml
│       ├── meson.yaml
│       ├── micro.yaml
│       ├── mpdconf.yaml
│       ├── msbuild.yaml
│       ├── nanorc.yaml
│       ├── nftables.yaml
│       ├── nginx.yaml
│       ├── nim.yaml
│       ├── nix.yaml
│       ├── nu.yaml
│       ├── objc.yaml
│       ├── ocaml.yaml
│       ├── octave.yaml
│       ├── odin.yaml
│       ├── pascal.yaml
│       ├── patch.yaml
│       ├── peg.yaml
│       ├── perl.yaml
│       ├── php.yaml
│       ├── pkg-config.yaml
│       ├── po.yaml
│       ├── pony.yaml
│       ├── pov.yaml
│       ├── privoxy-action.yaml
│       ├── privoxy-config.yaml
│       ├── privoxy-filter.yaml
│       ├── proto.yaml
│       ├── prql.yaml
│       ├── puppet.yaml
│       ├── python2.yaml
│       ├── python3.yaml
│       ├── r.yaml
│       ├── raku.yaml
│       ├── reST.yaml
│       ├── renpy.yaml
│       ├── rpmspec.yaml
│       ├── ruby.yaml
│       ├── rust.yaml
│       ├── sage.yaml
│       ├── scad.yaml
│       ├── scala.yaml
│       ├── sed.yaml
│       ├── sh.yaml
│       ├── sls.yaml
│       ├── smalltalk.yaml
│       ├── solidity.yaml
│       ├── sql.yaml
│       ├── stata.yaml
│       ├── svelte.yaml
│       ├── swift.yaml
│       ├── syntax_converter.go
│       ├── systemd.yaml
│       ├── tcl.yaml
│       ├── terraform.yaml
│       ├── tex.yaml
│       ├── toml.yaml
│       ├── twig.yaml
│       ├── typescript.yaml
│       ├── v.yaml
│       ├── vala.yaml
│       ├── verilog.yaml
│       ├── vhdl.yaml
│       ├── vi.yaml
│       ├── vue.yaml
│       ├── xml.yaml
│       ├── xresources.yaml
│       ├── yaml.yaml
│       ├── yum.yaml
│       ├── zig.yaml
│       ├── zscript.yaml
│       └── zsh.yaml
├── snapcraft.yaml
└── tools/
    ├── build-date.go
    ├── build-version.go
    ├── compile-linux.sh
    ├── cross-compile.sh
    ├── info-plist.go
    ├── nightly-release.sh
    ├── package-deb.sh
    ├── pre-release.sh
    ├── release.sh
    ├── remove-nightly-assets.go
    ├── testgen.go
    ├── update-nightly-tag.sh
    └── vendor-src.sh
Download .txt
SYMBOL INDEX (1331 symbols across 92 files)

FILE: cmd/micro/clean.go
  function shouldContinue (line 18) | func shouldContinue() bool {
  function CleanConfig (line 33) | func CleanConfig() {

FILE: cmd/micro/debug.go
  type NullWriter (line 11) | type NullWriter struct
    method Write (line 14) | func (NullWriter) Write(data []byte) (n int, err error) {
  function InitLog (line 19) | func InitLog() {

FILE: cmd/micro/initlua.go
  function init (line 20) | func init() {
  function LuaImport (line 26) | func LuaImport(pkg string) *lua.LTable {
  function luaImportMicro (line 43) | func luaImportMicro() *lua.LTable {
  function luaImportMicroConfig (line 67) | func luaImportMicroConfig() *lua.LTable {
  function luaImportMicroShell (line 98) | func luaImportMicroShell() *lua.LTable {
  function luaImportMicroBuffer (line 115) | func luaImportMicroBuffer() *lua.LTable {
  function luaImportMicroUtil (line 148) | func luaImportMicroUtil() *lua.LTable {

FILE: cmd/micro/micro.go
  function InitFlags (line 48) | func InitFlags() {
  function DoPluginFlags (line 131) | func DoPluginFlags() {
  function LoadInput (line 149) | func LoadInput(args []string) []*buffer.Buffer {
  function checkBackup (line 250) | func checkBackup(name string) error {
  function exit (line 279) | func exit(rc int) {
  function main (line 293) | func main() {
  function DoEvent (line 487) | func DoEvent() {

FILE: cmd/micro/micro_test.go
  function init (line 21) | func init() {
  function startup (line 25) | func startup(args []string) (tcell.SimulationScreen, error) {
  function cleanup (line 102) | func cleanup() {
  function handleEvent (line 106) | func handleEvent() {
  function injectKey (line 119) | func injectKey(key tcell.Key, r rune, mod tcell.ModMask) {
  function injectMouse (line 124) | func injectMouse(x, y int, buttons tcell.ButtonMask, mod tcell.ModMask) {
  function injectString (line 129) | func injectString(str string) {
  function openFile (line 152) | func openFile(file string) {
  function findBuffer (line 158) | func findBuffer(file string) *buffer.Buffer {
  function createTestFile (line 168) | func createTestFile(t *testing.T, content string) string {
  function TestMain (line 186) | func TestMain(m *testing.M) {
  function TestSimpleEdit (line 199) | func TestSimpleEdit(t *testing.T) {
  function TestMouse (line 231) | func TestMouse(t *testing.T) {
  function TestSearchAndReplace (line 292) | func TestSearchAndReplace(t *testing.T) {
  function TestMultiCursor (line 330) | func TestMultiCursor(t *testing.T) {
  function TestSettingsPersistence (line 334) | func TestSettingsPersistence(t *testing.T) {

FILE: internal/action/actions.go
  method ScrollUp (line 25) | func (h *BufPane) ScrollUp(n int) {
  method ScrollDown (line 32) | func (h *BufPane) ScrollDown(n int) {
  method ScrollAdjust (line 40) | func (h *BufPane) ScrollAdjust() {
  method ScrollReachedEnd (line 51) | func (h *BufPane) ScrollReachedEnd() bool {
  method MousePress (line 59) | func (h *BufPane) MousePress(e *tcell.EventMouse) bool {
  method MouseDrag (line 111) | func (h *BufPane) MouseDrag(e *tcell.EventMouse) bool {
  method MouseRelease (line 132) | func (h *BufPane) MouseRelease(e *tcell.EventMouse) bool {
  method ScrollUpAction (line 151) | func (h *BufPane) ScrollUpAction() bool {
  method ScrollDownAction (line 157) | func (h *BufPane) ScrollDownAction() bool {
  method Center (line 163) | func (h *BufPane) Center() bool {
  method CursorToViewTop (line 173) | func (h *BufPane) CursorToViewTop() bool {
  method CursorToViewCenter (line 189) | func (h *BufPane) CursorToViewCenter() bool {
  method CursorToViewBottom (line 201) | func (h *BufPane) CursorToViewBottom() bool {
  method MoveCursorUp (line 218) | func (h *BufPane) MoveCursorUp(n int) {
  method MoveCursorDown (line 237) | func (h *BufPane) MoveCursorDown(n int) {
  method CursorUp (line 256) | func (h *BufPane) CursorUp() bool {
  method CursorDown (line 264) | func (h *BufPane) CursorDown() bool {
  method CursorLeft (line 277) | func (h *BufPane) CursorLeft() bool {
  method CursorRight (line 302) | func (h *BufPane) CursorRight() bool {
  method WordRight (line 328) | func (h *BufPane) WordRight() bool {
  method WordLeft (line 336) | func (h *BufPane) WordLeft() bool {
  method SubWordRight (line 344) | func (h *BufPane) SubWordRight() bool {
  method SubWordLeft (line 352) | func (h *BufPane) SubWordLeft() bool {
  method SelectUp (line 360) | func (h *BufPane) SelectUp() bool {
  method SelectDown (line 371) | func (h *BufPane) SelectDown() bool {
  method SelectLeft (line 382) | func (h *BufPane) SelectLeft() bool {
  method SelectRight (line 398) | func (h *BufPane) SelectRight() bool {
  method SelectWordRight (line 414) | func (h *BufPane) SelectWordRight() bool {
  method SelectWordLeft (line 425) | func (h *BufPane) SelectWordLeft() bool {
  method SelectSubWordRight (line 436) | func (h *BufPane) SelectSubWordRight() bool {
  method SelectSubWordLeft (line 447) | func (h *BufPane) SelectSubWordLeft() bool {
  method StartOfText (line 458) | func (h *BufPane) StartOfText() bool {
  method StartOfTextToggle (line 467) | func (h *BufPane) StartOfTextToggle() bool {
  method StartOfLine (line 479) | func (h *BufPane) StartOfLine() bool {
  method EndOfLine (line 487) | func (h *BufPane) EndOfLine() bool {
  method SelectLine (line 495) | func (h *BufPane) SelectLine() bool {
  method SelectToStartOfText (line 502) | func (h *BufPane) SelectToStartOfText() bool {
  method SelectToStartOfTextToggle (line 514) | func (h *BufPane) SelectToStartOfTextToggle() bool {
  method SelectToStartOfLine (line 529) | func (h *BufPane) SelectToStartOfLine() bool {
  method SelectToEndOfLine (line 540) | func (h *BufPane) SelectToEndOfLine() bool {
  method paragraphPrevious (line 550) | func (h *BufPane) paragraphPrevious() {
  method paragraphNext (line 572) | func (h *BufPane) paragraphNext() {
  method ParagraphPrevious (line 597) | func (h *BufPane) ParagraphPrevious() bool {
  method ParagraphNext (line 607) | func (h *BufPane) ParagraphNext() bool {
  method SelectToParagraphPrevious (line 617) | func (h *BufPane) SelectToParagraphPrevious() bool {
  method SelectToParagraphNext (line 630) | func (h *BufPane) SelectToParagraphNext() bool {
  method Retab (line 642) | func (h *BufPane) Retab() bool {
  method CursorStart (line 649) | func (h *BufPane) CursorStart() bool {
  method CursorEnd (line 659) | func (h *BufPane) CursorEnd() bool {
  method SelectToStart (line 668) | func (h *BufPane) SelectToStart() bool {
  method SelectToEnd (line 679) | func (h *BufPane) SelectToEnd() bool {
  method InsertNewline (line 690) | func (h *BufPane) InsertNewline() bool {
  method Backspace (line 723) | func (h *BufPane) Backspace() bool {
  method DeleteWordRight (line 753) | func (h *BufPane) DeleteWordRight() bool {
  method DeleteWordLeft (line 764) | func (h *BufPane) DeleteWordLeft() bool {
  method DeleteSubWordRight (line 775) | func (h *BufPane) DeleteSubWordRight() bool {
  method DeleteSubWordLeft (line 786) | func (h *BufPane) DeleteSubWordLeft() bool {
  method Delete (line 797) | func (h *BufPane) Delete() bool {
  method IndentSelection (line 812) | func (h *BufPane) IndentSelection() bool {
  method IndentLine (line 847) | func (h *BufPane) IndentLine() bool {
  method OutdentLine (line 861) | func (h *BufPane) OutdentLine() bool {
  method OutdentSelection (line 878) | func (h *BufPane) OutdentSelection() bool {
  method Autocomplete (line 907) | func (h *BufPane) Autocomplete() bool {
  method CycleAutocompleteBack (line 933) | func (h *BufPane) CycleAutocompleteBack() bool {
  method InsertTab (line 946) | func (h *BufPane) InsertTab() bool {
  method SaveAll (line 957) | func (h *BufPane) SaveAll() bool {
  method SaveCB (line 965) | func (h *BufPane) SaveCB(action string, callback func()) bool {
  method Save (line 979) | func (h *BufPane) Save() bool {
  method SaveAsCB (line 985) | func (h *BufPane) SaveAsCB(action string, callback func()) bool {
  method SaveAs (line 1030) | func (h *BufPane) SaveAs() bool {
  method saveBufToFile (line 1037) | func (h *BufPane) saveBufToFile(filename string, action string, callback...
  method Find (line 1084) | func (h *BufPane) Find() bool {
  method FindLiteral (line 1089) | func (h *BufPane) FindLiteral() bool {
  method Search (line 1099) | func (h *BufPane) Search(str string, useRegex bool, searchDown bool) err...
  method find (line 1119) | func (h *BufPane) find(useRegex bool) bool {
  method ToggleHighlightSearch (line 1179) | func (h *BufPane) ToggleHighlightSearch() bool {
  method UnhighlightSearch (line 1185) | func (h *BufPane) UnhighlightSearch() bool {
  method ResetSearch (line 1194) | func (h *BufPane) ResetSearch() bool {
  method FindNext (line 1203) | func (h *BufPane) FindNext() bool {
  method FindPrevious (line 1240) | func (h *BufPane) FindPrevious() bool {
  method DiffNext (line 1277) | func (h *BufPane) DiffNext() bool {
  method DiffPrevious (line 1288) | func (h *BufPane) DiffPrevious() bool {
  method Undo (line 1299) | func (h *BufPane) Undo() bool {
  method Redo (line 1309) | func (h *BufPane) Redo() bool {
  method selectLines (line 1318) | func (h *BufPane) selectLines() int {
  method Copy (line 1345) | func (h *BufPane) Copy() bool {
  method CopyLine (line 1358) | func (h *BufPane) CopyLine() bool {
  method Cut (line 1385) | func (h *BufPane) Cut() bool {
  method CutLine (line 1401) | func (h *BufPane) CutLine() bool {
  method Duplicate (line 1432) | func (h *BufPane) Duplicate() bool {
  method DuplicateLine (line 1444) | func (h *BufPane) DuplicateLine() bool {
  method DeleteLine (line 1488) | func (h *BufPane) DeleteLine() bool {
  method MoveLinesUp (line 1506) | func (h *BufPane) MoveLinesUp() bool {
  method MoveLinesDown (line 1550) | func (h *BufPane) MoveLinesDown() bool {
  method Paste (line 1589) | func (h *BufPane) Paste() bool {
  method PastePrimary (line 1601) | func (h *BufPane) PastePrimary() bool {
  method paste (line 1612) | func (h *BufPane) paste(clip string) {
  method JumpToMatchingBrace (line 1637) | func (h *BufPane) JumpToMatchingBrace() bool {
  method SelectAll (line 1656) | func (h *BufPane) SelectAll() bool {
  method OpenFile (line 1667) | func (h *BufPane) OpenFile() bool {
  method JumpLine (line 1677) | func (h *BufPane) JumpLine() bool {
  method Start (line 1687) | func (h *BufPane) Start() bool {
  method End (line 1695) | func (h *BufPane) End() bool {
  method PageUp (line 1703) | func (h *BufPane) PageUp() bool {
  method PageDown (line 1710) | func (h *BufPane) PageDown() bool {
  method SelectPageUp (line 1718) | func (h *BufPane) SelectPageUp() bool {
  method SelectPageDown (line 1734) | func (h *BufPane) SelectPageDown() bool {
  method CursorPageUp (line 1752) | func (h *BufPane) CursorPageUp() bool {
  method CursorPageDown (line 1766) | func (h *BufPane) CursorPageDown() bool {
  method HalfPageUp (line 1787) | func (h *BufPane) HalfPageUp() bool {
  method HalfPageDown (line 1793) | func (h *BufPane) HalfPageDown() bool {
  method ToggleDiffGutter (line 1800) | func (h *BufPane) ToggleDiffGutter() bool {
  method ToggleRuler (line 1813) | func (h *BufPane) ToggleRuler() bool {
  method ClearStatus (line 1825) | func (h *BufPane) ClearStatus() bool {
  method ToggleHelp (line 1830) | func (h *BufPane) ToggleHelp() bool {
  method ToggleKeyMenu (line 1841) | func (h *BufPane) ToggleKeyMenu() bool {
  method ShellMode (line 1848) | func (h *BufPane) ShellMode() bool {
  method CommandMode (line 1860) | func (h *BufPane) CommandMode() bool {
  method ToggleOverwriteMode (line 1870) | func (h *BufPane) ToggleOverwriteMode() bool {
  method Escape (line 1876) | func (h *BufPane) Escape() bool {
  method Deselect (line 1881) | func (h *BufPane) Deselect() bool {
  method ClearInfo (line 1890) | func (h *BufPane) ClearInfo() bool {
  method ForceQuit (line 1900) | func (h *BufPane) ForceQuit() bool {
  method closePrompt (line 1916) | func (h *BufPane) closePrompt(action string, callback func()) {
  method Quit (line 1927) | func (h *BufPane) Quit() bool {
  method QuitAll (line 1946) | func (h *BufPane) QuitAll() bool {
  method AddTab (line 1976) | func (h *BufPane) AddTab() bool {
  method PreviousTab (line 1988) | func (h *BufPane) PreviousTab() bool {
  method NextTab (line 1997) | func (h *BufPane) NextTab() bool {
  method FirstTab (line 2006) | func (h *BufPane) FirstTab() bool {
  method LastTab (line 2015) | func (h *BufPane) LastTab() bool {
  method VSplitAction (line 2025) | func (h *BufPane) VSplitAction() bool {
  method HSplitAction (line 2032) | func (h *BufPane) HSplitAction() bool {
  method Unsplit (line 2039) | func (h *BufPane) Unsplit() bool {
  method NextSplit (line 2054) | func (h *BufPane) NextSplit() bool {
  method PreviousSplit (line 2063) | func (h *BufPane) PreviousSplit() bool {
  method FirstSplit (line 2072) | func (h *BufPane) FirstSplit() bool {
  method LastSplit (line 2081) | func (h *BufPane) LastSplit() bool {
  method ToggleMacro (line 2094) | func (h *BufPane) ToggleMacro() bool {
  method PlayMacro (line 2107) | func (h *BufPane) PlayMacro() bool {
  method SpawnMultiCursor (line 2124) | func (h *BufPane) SpawnMultiCursor() bool {
  method SpawnCursorAtLoc (line 2165) | func (h *BufPane) SpawnCursorAtLoc(loc buffer.Loc) *buffer.Cursor {
  method SpawnMultiCursorUpN (line 2173) | func (h *BufPane) SpawnMultiCursorUpN(n int) bool {
  method SpawnMultiCursorUp (line 2199) | func (h *BufPane) SpawnMultiCursorUp() bool {
  method SpawnMultiCursorDown (line 2204) | func (h *BufPane) SpawnMultiCursorDown() bool {
  method SpawnMultiCursorSelect (line 2209) | func (h *BufPane) SpawnMultiCursorSelect() bool {
  method MouseMultiCursor (line 2244) | func (h *BufPane) MouseMultiCursor(e *tcell.EventMouse) bool {
  method skipMultiCursor (line 2270) | func (h *BufPane) skipMultiCursor(forward bool) bool {
  method SkipMultiCursor (line 2308) | func (h *BufPane) SkipMultiCursor() bool {
  method SkipMultiCursorBack (line 2313) | func (h *BufPane) SkipMultiCursorBack() bool {
  method RemoveMultiCursor (line 2318) | func (h *BufPane) RemoveMultiCursor() bool {
  method RemoveAllMultiCursors (line 2334) | func (h *BufPane) RemoveAllMultiCursors() bool {
  method None (line 2346) | func (h *BufPane) None() bool {

FILE: internal/action/actions_other.go
  method Suspend (line 5) | func (*BufPane) Suspend() bool {

FILE: internal/action/actions_posix.go
  method Suspend (line 14) | func (*BufPane) Suspend() bool {

FILE: internal/action/bindings.go
  function writeFile (line 27) | func writeFile(name string, txt []byte) error {
  function createBindingsIfNotExist (line 31) | func createBindingsIfNotExist(fname string) {
  function InitBindings (line 38) | func InitBindings() {
  function BindKey (line 89) | func BindKey(k, v string, bind func(e Event, a string)) {
  function findEvents (line 116) | func findEvents(k string) (b KeySequenceEvent, ok bool, err error) {
  function findSingleEvent (line 143) | func findSingleEvent(k string) (b Event, ok bool) {
  function findEvent (line 229) | func findEvent(k string) (Event, error) {
  function eventsEqual (line 246) | func eventsEqual(e1 Event, e2 Event) bool {
  function TryBindKeyPlug (line 266) | func TryBindKeyPlug(k, v string, overwrite bool) (bool, error) {
  function TryBindKey (line 275) | func TryBindKey(k, v string, overwrite bool, writeToFile bool) (bool, er...
  function UnbindKey (line 333) | func UnbindKey(k string) error {

FILE: internal/action/bufpane.go
  type BufAction (line 19) | type BufAction
  type BufKeyAction (line 22) | type BufKeyAction
  type BufMouseAction (line 25) | type BufMouseAction
  function BufKeyActionGeneral (line 31) | func BufKeyActionGeneral(a BufKeyAction) PaneKeyAction {
  function BufMouseActionGeneral (line 38) | func BufMouseActionGeneral(a BufMouseAction) PaneMouseAction {
  function init (line 44) | func init() {
  function LuaAction (line 50) | func LuaAction(fn string, k Event) BufAction {
  function BufMapEvent (line 92) | func BufMapEvent(k Event, action string) {
  function BufUnmap (line 191) | func BufUnmap(k Event) {
  type BufPane (line 206) | type BufPane struct
    method finishInitialize (line 289) | func (h *BufPane) finishInitialize() {
    method Resize (line 300) | func (h *BufPane) Resize(width, height int) {
    method SetTab (line 308) | func (h *BufPane) SetTab(t *Tab) {
    method Tab (line 313) | func (h *BufPane) Tab() *Tab {
    method ResizePane (line 317) | func (h *BufPane) ResizePane(size int) {
    method PluginCB (line 327) | func (h *BufPane) PluginCB(cb string, args ...any) bool {
    method resetMouse (line 340) | func (h *BufPane) resetMouse() {
    method OpenBuffer (line 347) | func (h *BufPane) OpenBuffer(b *buffer.Buffer) {
    method GotoLoc (line 362) | func (h *BufPane) GotoLoc(loc buffer.Loc) {
    method initialRelocate (line 380) | func (h *BufPane) initialRelocate() {
    method ID (line 398) | func (h *BufPane) ID() uint64 {
    method SetID (line 403) | func (h *BufPane) SetID(i uint64) {
    method Name (line 408) | func (h *BufPane) Name() string {
    method ReOpen (line 417) | func (h *BufPane) ReOpen() {
    method getReloadSetting (line 422) | func (h *BufPane) getReloadSetting() string {
    method HandleEvent (line 428) | func (h *BufPane) HandleEvent(event tcell.Event) {
    method Bindings (line 530) | func (h *BufPane) Bindings() *KeyTree {
    method DoKeyEvent (line 542) | func (h *BufPane) DoKeyEvent(e Event) bool {
    method execAction (line 555) | func (h *BufPane) execAction(action BufAction, name string, te *tcell....
    method completeAction (line 584) | func (h *BufPane) completeAction(action string) {
    method HasKeyEvent (line 588) | func (h *BufPane) HasKeyEvent(e Event) bool {
    method DoMouseEvent (line 597) | func (h *BufPane) DoMouseEvent(e MouseEvent, te *tcell.EventMouse) bool {
    method DoRuneInsert (line 621) | func (h *BufPane) DoRuneInsert(r rune) {
    method VSplitIndex (line 651) | func (h *BufPane) VSplitIndex(buf *buffer.Buffer, right bool) *BufPane {
    method HSplitIndex (line 665) | func (h *BufPane) HSplitIndex(buf *buffer.Buffer, bottom bool) *BufPane {
    method VSplitBuf (line 679) | func (h *BufPane) VSplitBuf(buf *buffer.Buffer) *BufPane {
    method HSplitBuf (line 684) | func (h *BufPane) HSplitBuf(buf *buffer.Buffer) *BufPane {
    method Close (line 689) | func (h *BufPane) Close() {
    method SetActive (line 694) | func (h *BufPane) SetActive(b bool) {
  function newBufPane (line 259) | func newBufPane(buf *buffer.Buffer, win display.BWindow, tab *Tab) *BufP...
  function NewBufPane (line 272) | func NewBufPane(buf *buffer.Buffer, win display.BWindow, tab *Tab) *BufP...
  function NewBufPaneFromBuf (line 280) | func NewBufPaneFromBuf(buf *buffer.Buffer, tab *Tab) *BufPane {

FILE: internal/action/command.go
  type Command (line 26) | type Command struct
  function InitCommands (line 33) | func InitCommands() {
  function MakeCommand (line 75) | func MakeCommand(name string, action func(bp *BufPane, args []string), c...
  function CommandEditAction (line 84) | func CommandEditAction(prompt string) BufKeyAction {
  function CommandAction (line 97) | func CommandAction(cmd string) BufKeyAction {
  method PluginCmd (line 107) | func (h *BufPane) PluginCmd(args []string) {
  method RetabCmd (line 122) | func (h *BufPane) RetabCmd(args []string) {
  method RawCmd (line 128) | func (h *BufPane) RawCmd(args []string) {
  method TextFilterCmd (line 139) | func (h *BufPane) TextFilterCmd(args []string) {
  method TabMoveCmd (line 180) | func (h *BufPane) TabMoveCmd(args []string) {
  method TabSwitchCmd (line 230) | func (h *BufPane) TabSwitchCmd(args []string) {
  method CdCmd (line 258) | func (h *BufPane) CdCmd(args []string) {
  method MemUsageCmd (line 289) | func (h *BufPane) MemUsageCmd(args []string) {
  method PwdCmd (line 294) | func (h *BufPane) PwdCmd(args []string) {
  method OpenCmd (line 304) | func (h *BufPane) OpenCmd(args []string) {
  method ToggleLogCmd (line 325) | func (h *BufPane) ToggleLogCmd(args []string) {
  method ReloadCmd (line 334) | func (h *BufPane) ReloadCmd(args []string) {
  function ReloadConfig (line 339) | func ReloadConfig() {
  function reloadRuntime (line 343) | func reloadRuntime(reloadPlugins bool) {
  method ReopenCmd (line 415) | func (h *BufPane) ReopenCmd(args []string) {
  method openHelp (line 430) | func (h *BufPane) openHelp(page string, hsplit bool, forceSplit bool) er...
  method HelpCmd (line 454) | func (h *BufPane) HelpCmd(args []string) {
  method VSplitCmd (line 508) | func (h *BufPane) VSplitCmd(args []string) {
  method HSplitCmd (line 528) | func (h *BufPane) HSplitCmd(args []string) {
  method EvalCmd (line 547) | func (h *BufPane) EvalCmd(args []string) {
  method NewTabCmd (line 553) | func (h *BufPane) NewTabCmd(args []string) {
  function doSetGlobalOptionNative (line 575) | func doSetGlobalOptionNative(option string, nativeValue any) error {
  function SetGlobalOptionNative (line 634) | func SetGlobalOptionNative(option string, nativeValue any, writeToFile b...
  function SetGlobalOption (line 673) | func SetGlobalOption(option, value string, writeToFile bool) error {
  function SetGlobalOptionNativePlug (line 686) | func SetGlobalOptionNativePlug(option string, nativeValue any) error {
  function SetGlobalOptionPlug (line 690) | func SetGlobalOptionPlug(option, value string) error {
  method ResetCmd (line 695) | func (h *BufPane) ResetCmd(args []string) {
  method SetCmd (line 712) | func (h *BufPane) SetCmd(args []string) {
  method SetLocalCmd (line 733) | func (h *BufPane) SetLocalCmd(args []string) {
  method toggleOption (line 748) | func (h *BufPane) toggleOption(option string, local bool) error {
  method ToggleCmd (line 786) | func (h *BufPane) ToggleCmd(args []string) {
  method ToggleLocalCmd (line 797) | func (h *BufPane) ToggleLocalCmd(args []string) {
  method ShowCmd (line 808) | func (h *BufPane) ShowCmd(args []string) {
  function parseKeyArg (line 829) | func parseKeyArg(arg string) string {
  method ShowKeyCmd (line 835) | func (h *BufPane) ShowKeyCmd(args []string) {
  method BindCmd (line 854) | func (h *BufPane) BindCmd(args []string) {
  method UnbindCmd (line 871) | func (h *BufPane) UnbindCmd(args []string) {
  method RunCmd (line 888) | func (h *BufPane) RunCmd(args []string) {
  method QuitCmd (line 901) | func (h *BufPane) QuitCmd(args []string) {
  method GotoCmd (line 908) | func (h *BufPane) GotoCmd(args []string) {
  method JumpCmd (line 929) | func (h *BufPane) JumpCmd(args []string) {
  method parseLineCol (line 946) | func (h *BufPane) parseLineCol(args []string) (line int, col int, err er...
  method SaveCmd (line 973) | func (h *BufPane) SaveCmd(args []string) {
  method ReplaceCmd (line 982) | func (h *BufPane) ReplaceCmd(args []string) {
  method ReplaceAllCmd (line 1131) | func (h *BufPane) ReplaceAllCmd(args []string) {
  method openTerm (line 1136) | func (h *BufPane) openTerm(args []string, newtab bool) {
  method TermCmd (line 1171) | func (h *BufPane) TermCmd(args []string) {
  method HandleCommand (line 1203) | func (h *BufPane) HandleCommand(input string) {

FILE: internal/action/defaults.go
  function DefaultBindings (line 10) | func DefaultBindings(pane string) map[string]string {

FILE: internal/action/events.go
  type Event (line 12) | type Event interface
  type RawEvent (line 19) | type RawEvent struct
    method Name (line 23) | func (r RawEvent) Name() string {
  type KeyEvent (line 32) | type KeyEvent struct
    method Name (line 58) | func (k KeyEvent) Name() string {
  function metaToAlt (line 39) | func metaToAlt(mod tcell.ModMask) tcell.ModMask {
  function keyEvent (line 47) | func keyEvent(e *tcell.EventKey) KeyEvent {
  type KeySequenceEvent (line 100) | type KeySequenceEvent struct
    method Name (line 104) | func (k KeySequenceEvent) Name() string {
  type MouseState (line 114) | type MouseState
  constant MousePress (line 117) | MousePress = iota
  constant MouseDrag (line 118) | MouseDrag
  constant MouseRelease (line 119) | MouseRelease
  type MouseEvent (line 124) | type MouseEvent struct
    method Name (line 130) | func (m MouseEvent) Name() string {
  function ConstructEvent (line 166) | func ConstructEvent(event tcell.Event) (Event, error) {
  type Handler (line 185) | type Handler interface

FILE: internal/action/globals.go
  function InitGlobals (line 12) | func InitGlobals() {
  function GetInfoBar (line 19) | func GetInfoBar() *InfoPane {
  function WriteLog (line 24) | func WriteLog(s string) {
  method OpenLogBuf (line 34) | func (h *BufPane) OpenLogBuf() {

FILE: internal/action/infocomplete.go
  function CommandComplete (line 19) | func CommandComplete(b *buffer.Buffer) ([]string, []string) {
  function HelpComplete (line 40) | func HelpComplete(b *buffer.Buffer) ([]string, []string) {
  function colorschemeComplete (line 63) | func colorschemeComplete(input string) (string, []string) {
  function filetypeComplete (line 82) | func filetypeComplete(input string) (string, []string) {
  function OptionComplete (line 139) | func OptionComplete(b *buffer.Buffer) ([]string, []string) {
  function OptionValueComplete (line 164) | func OptionValueComplete(b *buffer.Buffer) ([]string, []string) {
  function PluginCmdComplete (line 253) | func PluginCmdComplete(b *buffer.Buffer) ([]string, []string) {
  function PluginComplete (line 273) | func PluginComplete(b *buffer.Buffer) ([]string, []string) {

FILE: internal/action/infopane.go
  type InfoKeyAction (line 14) | type InfoKeyAction
  function init (line 19) | func init() {
  function InfoMapEvent (line 24) | func InfoMapEvent(k Event, action string) {
  function infoMapKey (line 35) | func infoMapKey(k Event, action string) {
  function infoMapMouse (line 43) | func infoMapMouse(k MouseEvent, action string) {
  function InfoKeyActionGeneral (line 52) | func InfoKeyActionGeneral(a InfoKeyAction) PaneKeyAction {
  type InfoPane (line 59) | type InfoPane struct
    method Close (line 79) | func (h *InfoPane) Close() {
    method HandleEvent (line 84) | func (h *InfoPane) HandleEvent(event tcell.Event) {
    method DoKeyEvent (line 129) | func (h *InfoPane) DoKeyEvent(e KeyEvent) bool {
    method HistoryUp (line 170) | func (h *InfoPane) HistoryUp() {
    method HistoryDown (line 175) | func (h *InfoPane) HistoryDown() {
    method HistorySearchUp (line 181) | func (h *InfoPane) HistorySearchUp() {
    method HistorySearchDown (line 187) | func (h *InfoPane) HistorySearchDown() {
    method CommandComplete (line 192) | func (h *InfoPane) CommandComplete() {
    method ExecuteCommand (line 221) | func (h *InfoPane) ExecuteCommand() {
    method AbortCommand (line 228) | func (h *InfoPane) AbortCommand() {
  function NewInfoPane (line 64) | func NewInfoPane(ib *info.InfoBuf, w display.BWindow, tab *Tab) *InfoPane {
  function NewInfoBar (line 73) | func NewInfoBar() *InfoPane {

FILE: internal/action/keytree.go
  type PaneKeyAction (line 9) | type PaneKeyAction
  type PaneMouseAction (line 10) | type PaneMouseAction
  type PaneKeyAnyAction (line 11) | type PaneKeyAnyAction
  type KeyTreeNode (line 17) | type KeyTreeNode struct
  function NewKeyTreeNode (line 27) | func NewKeyTreeNode() *KeyTreeNode {
  type TreeAction (line 36) | type TreeAction struct
  type KeyTree (line 49) | type KeyTree struct
    method RegisterKeyBinding (line 111) | func (k *KeyTree) RegisterKeyBinding(e Event, a PaneKeyAction) {
    method RegisterKeyAnyBinding (line 122) | func (k *KeyTree) RegisterKeyAnyBinding(e Event, a PaneKeyAnyAction) {
    method RegisterMouseBinding (line 133) | func (k *KeyTree) RegisterMouseBinding(e Event, a PaneMouseAction) {
    method registerBinding (line 142) | func (k *KeyTree) registerBinding(e Event, a TreeAction) {
    method NextEvent (line 179) | func (k *KeyTree) NextEvent(e Event, mouse *tcell.EventMouse) (PaneKey...
    method ResetEvents (line 225) | func (k *KeyTree) ResetEvents() {
    method RecordedEventsStr (line 233) | func (k *KeyTree) RecordedEventsStr() string {
    method DeleteBinding (line 243) | func (k *KeyTree) DeleteBinding(e Event) {
    method DeleteAllBindings (line 249) | func (k *KeyTree) DeleteAllBindings(e Event) {
    method SetMode (line 254) | func (k *KeyTree) SetMode(mode string, en bool) {
    method HasMode (line 259) | func (k *KeyTree) HasMode(mode string) bool {
  type KeyTreeCursor (line 60) | type KeyTreeCursor struct
    method MakeClosure (line 71) | func (k *KeyTreeCursor) MakeClosure(a TreeAction) PaneKeyAction {
  function NewKeyTree (line 88) | func NewKeyTree() *KeyTree {
  type ModeConstraint (line 105) | type ModeConstraint struct

FILE: internal/action/pane.go
  type Pane (line 8) | type Pane interface

FILE: internal/action/rawpane.go
  type RawPane (line 12) | type RawPane struct
    method HandleEvent (line 32) | func (h *RawPane) HandleEvent(event tcell.Event) {
  function NewRawPaneFromWin (line 16) | func NewRawPaneFromWin(b *buffer.Buffer, win display.BWindow, tab *Tab) ...
  function NewRawPane (line 23) | func NewRawPane(tab *Tab) *RawPane {

FILE: internal/action/tab.go
  type TabList (line 17) | type TabList struct
    method UpdateNames (line 44) | func (t *TabList) UpdateNames() {
    method AddTab (line 52) | func (t *TabList) AddTab(p *Tab) {
    method RemoveTab (line 59) | func (t *TabList) RemoveTab(id uint64) {
    method Resize (line 82) | func (t *TabList) Resize() {
    method HandleEvent (line 102) | func (t *TabList) HandleEvent(event tcell.Event) {
    method Display (line 145) | func (t *TabList) Display() {
    method SetActive (line 152) | func (t *TabList) SetActive(a int) {
    method ResetMouse (line 175) | func (t *TabList) ResetMouse() {
    method CloseTerms (line 192) | func (t *TabList) CloseTerms() {
  function NewTabList (line 24) | func NewTabList(bufs []*buffer.Buffer) *TabList {
  function InitTabs (line 205) | func InitTabs(bufs []*buffer.Buffer) {
  function MainTab (line 223) | func MainTab() *Tab {
  type Tab (line 231) | type Tab struct
    method HandleEvent (line 276) | func (t *Tab) HandleEvent(event tcell.Event) {
    method SetActive (line 341) | func (t *Tab) SetActive(i int) {
    method AddPane (line 353) | func (t *Tab) AddPane(pane Pane, i int) {
    method GetPane (line 363) | func (t *Tab) GetPane(splitid uint64) int {
    method RemovePane (line 373) | func (t *Tab) RemovePane(i int) {
    method Resize (line 380) | func (t *Tab) Resize() {
    method CurPane (line 395) | func (t *Tab) CurPane() *BufPane {
  function NewTabFromBuffer (line 246) | func NewTabFromBuffer(x, y, width, height int, b *buffer.Buffer) *Tab {
  function NewTabFromPane (line 259) | func NewTabFromPane(x, y, width, height int, pane Pane) *Tab {

FILE: internal/action/terminal_supported.go
  constant TermEmuSupported (line 11) | TermEmuSupported = true
  function RunTermEmulator (line 17) | func RunTermEmulator(h *BufPane, input string, wait bool, getOutput bool...

FILE: internal/action/terminal_unsupported.go
  constant TermEmuSupported (line 8) | TermEmuSupported = false
  function RunTermEmulator (line 11) | func RunTermEmulator(input string, wait bool, getOutput bool, callback f...

FILE: internal/action/termpane.go
  type TermKeyAction (line 16) | type TermKeyAction
  function init (line 20) | func init() {
  function TermKeyActionGeneral (line 24) | func TermKeyActionGeneral(a TermKeyAction) PaneKeyAction {
  function TermMapEvent (line 31) | func TermMapEvent(k Event, action string) {
  function termMapKey (line 42) | func termMapKey(k Event, action string) {
  function termMapMouse (line 48) | func termMapMouse(k MouseEvent, action string) {
  type TermPane (line 53) | type TermPane struct
    method ID (line 76) | func (t *TermPane) ID() uint64 {
    method SetID (line 80) | func (t *TermPane) SetID(i uint64) {
    method Name (line 84) | func (t *TermPane) Name() string {
    method SetTab (line 88) | func (t *TermPane) SetTab(tab *Tab) {
    method Tab (line 92) | func (t *TermPane) Tab() *Tab {
    method Close (line 96) | func (t *TermPane) Close() {}
    method Quit (line 99) | func (t *TermPane) Quit() {
    method Unsplit (line 113) | func (t *TermPane) Unsplit() {
    method HandleEvent (line 126) | func (t *TermPane) HandleEvent(event tcell.Event) {
    method HandleTermClose (line 196) | func (t *TermPane) HandleTermClose() {
    method Exit (line 203) | func (t *TermPane) Exit() {
    method CommandMode (line 209) | func (t *TermPane) CommandMode() {
    method NextSplit (line 218) | func (t *TermPane) NextSplit() {
    method HandleCommand (line 230) | func (t *TermPane) HandleCommand(input string) {
  function NewTermPane (line 62) | func NewTermPane(x, y, w, h int, t *shell.Terminal, id uint64, tab *Tab)...

FILE: internal/buffer/autocomplete.go
  type Completer (line 20) | type Completer
  method GetSuggestions (line 22) | func (b *Buffer) GetSuggestions() {
  method Autocomplete (line 27) | func (b *Buffer) Autocomplete(c Completer) bool {
  method CycleAutocomplete (line 38) | func (b *Buffer) CycleAutocomplete(forward bool) {
  method GetWord (line 67) | func (b *Buffer) GetWord() ([]byte, int) {
  method GetArg (line 86) | func (b *Buffer) GetArg() (string, int) {
  function FileComplete (line 105) | func FileComplete(b *Buffer) ([]string, []string) {
  function BufferComplete (line 154) | func BufferComplete(b *Buffer) ([]string, []string) {

FILE: internal/buffer/backup.go
  constant BackupMsg (line 15) | BackupMsg = `A backup was detected for:
  constant backupSeconds (line 35) | backupSeconds = 8
  type backupRequestType (line 37) | type backupRequestType
  constant backupCreate (line 40) | backupCreate = iota
  constant backupRemove (line 41) | backupRemove
  type backupRequest (line 44) | type backupRequest struct
  function init (line 51) | func init() {
  method RequestBackup (line 55) | func (b *SharedBuffer) RequestBackup() {
  method CancelBackup (line 59) | func (b *SharedBuffer) CancelBackup() {
  function handleBackupRequest (line 63) | func handleBackupRequest(br backupRequest) {
  function periodicBackup (line 74) | func periodicBackup() {
  method backupDir (line 83) | func (b *SharedBuffer) backupDir() string {
  method keepBackup (line 91) | func (b *SharedBuffer) keepBackup() bool {
  method writeBackup (line 95) | func (b *SharedBuffer) writeBackup(path string) (string, string, error) {
  method removeBackup (line 130) | func (b *SharedBuffer) removeBackup(path string, resolveName string) {
  method Backup (line 138) | func (b *SharedBuffer) Backup() error {
  method RemoveBackup (line 148) | func (b *SharedBuffer) RemoveBackup() {
  method ApplyBackup (line 158) | func (b *SharedBuffer) ApplyBackup(fsize int64) (bool, bool) {

FILE: internal/buffer/buffer.go
  type BufType (line 41) | type BufType struct
  type SharedBuffer (line 68) | type SharedBuffer struct
    method insert (line 126) | func (b *SharedBuffer) insert(pos Loc, value []byte) {
    method remove (line 135) | func (b *SharedBuffer) remove(start, end Loc) []byte {
    method setModified (line 142) | func (b *SharedBuffer) setModified() {
    method calcHash (line 164) | func (b *SharedBuffer) calcHash(out *[md5.Size]byte) {
    method MarkModified (line 185) | func (b *SharedBuffer) MarkModified(start, end int) {
    method DisableReload (line 205) | func (b *SharedBuffer) DisableReload() {
  constant DSUnchanged (line 210) | DSUnchanged    = 0
  constant DSAdded (line 211) | DSAdded        = 1
  constant DSModified (line 212) | DSModified     = 2
  constant DSDeletedAbove (line 213) | DSDeletedAbove = 3
  type DiffStatus (line 216) | type DiffStatus
  type Command (line 218) | type Command struct
  type Buffer (line 238) | type Buffer struct
    method Close (line 512) | func (b *Buffer) Close() {
    method Fini (line 526) | func (b *Buffer) Fini() {
    method GetName (line 539) | func (b *Buffer) GetName() string {
    method SetName (line 554) | func (b *Buffer) SetName(s string) {
    method Insert (line 559) | func (b *Buffer) Insert(start Loc, text string) {
    method Remove (line 568) | func (b *Buffer) Remove(start, end Loc) {
    method FileType (line 577) | func (b *Buffer) FileType() string {
    method ExternallyModified (line 583) | func (b *Buffer) ExternallyModified() bool {
    method UpdateModTime (line 592) | func (b *Buffer) UpdateModTime() (err error) {
    method ReOpen (line 598) | func (b *Buffer) ReOpen() error {
    method RelocateCursors (line 633) | func (b *Buffer) RelocateCursors() {
    method DeselectCursors (line 640) | func (b *Buffer) DeselectCursors() {
    method RuneAt (line 647) | func (b *Buffer) RuneAt(loc Loc) rune {
    method WordAt (line 666) | func (b *Buffer) WordAt(loc Loc) []byte {
    method Shared (line 687) | func (b *Buffer) Shared() bool {
    method Modified (line 698) | func (b *Buffer) Modified() bool {
    method Size (line 703) | func (b *Buffer) Size() int {
    method UpdateRules (line 817) | func (b *Buffer) UpdateRules() {
    method ClearMatches (line 1014) | func (b *Buffer) ClearMatches() {
    method IndentString (line 1023) | func (b *Buffer) IndentString(tabsize int) string {
    method SetCursors (line 1031) | func (b *Buffer) SetCursors(c []*Cursor) {
    method AddCursor (line 1038) | func (b *Buffer) AddCursor(c *Cursor) {
    method SetCurCursor (line 1046) | func (b *Buffer) SetCurCursor(n int) {
    method GetActiveCursor (line 1051) | func (b *Buffer) GetActiveCursor() *Cursor {
    method GetCursor (line 1056) | func (b *Buffer) GetCursor(n int) *Cursor {
    method GetCursors (line 1061) | func (b *Buffer) GetCursors() []*Cursor {
    method NumCursors (line 1066) | func (b *Buffer) NumCursors() int {
    method MergeCursors (line 1072) | func (b *Buffer) MergeCursors() {
    method UpdateCursors (line 1101) | func (b *Buffer) UpdateCursors() {
    method RemoveCursor (line 1109) | func (b *Buffer) RemoveCursor(i int) {
    method ClearCursors (line 1118) | func (b *Buffer) ClearCursors() {
    method MoveLinesUp (line 1129) | func (b *Buffer) MoveLinesUp(start int, end int) {
    method MoveLinesDown (line 1154) | func (b *Buffer) MoveLinesDown(start int, end int) {
    method findMatchingBrace (line 1176) | func (b *Buffer) findMatchingBrace(braceType [2]rune, start Loc, char ...
    method FindMatchingBrace (line 1225) | func (b *Buffer) FindMatchingBrace(start Loc) (Loc, bool, bool) {
    method Retab (line 1265) | func (b *Buffer) Retab() {
    method Line (line 1319) | func (b *Buffer) Line(i int) string {
    method Write (line 1323) | func (b *Buffer) Write(bytes []byte) (n int, err error) {
    method updateDiff (line 1328) | func (b *Buffer) updateDiff(synchronous bool) {
    method UpdateDiff (line 1379) | func (b *Buffer) UpdateDiff() {
    method SetDiffBase (line 1406) | func (b *Buffer) SetDiffBase(diffBase []byte) {
    method DiffStatus (line 1417) | func (b *Buffer) DiffStatus(lineN int) DiffStatus {
    method FindNextDiffLine (line 1426) | func (b *Buffer) FindNextDiffLine(startLine int, forward bool) (int, e...
    method SearchMatch (line 1461) | func (b *Buffer) SearchMatch(pos Loc) bool {
  function NewBufferFromFileWithCommand (line 275) | func NewBufferFromFileWithCommand(path string, btype BufType, cmd Comman...
  function NewBufferFromFile (line 337) | func NewBufferFromFile(path string, btype BufType) (*Buffer, error) {
  function NewBufferFromStringWithCommand (line 343) | func NewBufferFromStringWithCommand(text, path string, btype BufType, cm...
  function NewBufferFromString (line 348) | func NewBufferFromString(text, path string, btype BufType) *Buffer {
  function NewBuffer (line 357) | func NewBuffer(r io.Reader, size int64, path string, btype BufType, cmd ...
  function CloseOpenBuffers (line 503) | func CloseOpenBuffers() {
  function parseDefFromFile (line 718) | func parseDefFromFile(f config.RuntimeFile, header *highlight.Header) *h...
  function findRealRuntimeSyntaxDef (line 750) | func findRealRuntimeSyntaxDef(name string, header *highlight.Header) *hi...
  function findRuntimeSyntaxDef (line 764) | func findRuntimeSyntaxDef(name string, header *highlight.Header) *highli...
  function resolveIncludes (line 776) | func resolveIncludes(syndef *highlight.Def) {
  function ParseCursorLocation (line 1295) | func ParseCursorLocation(cursorPositions []string) (Loc, error) {
  function WriteLog (line 1466) | func WriteLog(s string) {
  function GetLogBuf (line 1471) | func GetLogBuf() *Buffer {

FILE: internal/buffer/buffer_generated_test.go
  function TestAuto1 (line 8) | func TestAuto1(t *testing.T) {
  function TestAuto2 (line 49) | func TestAuto2(t *testing.T) {
  function TestAuto3 (line 98) | func TestAuto3(t *testing.T) {
  function TestAuto4 (line 137) | func TestAuto4(t *testing.T) {
  function TestBug19872UndoIsFunky (line 202) | func TestBug19872UndoIsFunky(t *testing.T) {
  function TestBug19872UndoIsFunky_2 (line 237) | func TestBug19872UndoIsFunky_2(t *testing.T) {
  function TestInsertEmptyText (line 273) | func TestInsertEmptyText(t *testing.T) {
  function TestLastOpIsNoOp (line 302) | func TestLastOpIsNoOp(t *testing.T) {
  function TestInsertTextWithoutNewline1 (line 338) | func TestInsertTextWithoutNewline1(t *testing.T) {
  function TestInsertTextWithoutNewline2 (line 367) | func TestInsertTextWithoutNewline2(t *testing.T) {
  function TestInsertOneNewline (line 396) | func TestInsertOneNewline(t *testing.T) {
  function TestInsertTextWithOneNewline (line 427) | func TestInsertTextWithOneNewline(t *testing.T) {
  function TestInsertTextWithTwoNewlines (line 458) | func TestInsertTextWithTwoNewlines(t *testing.T) {
  function TestInsertTextWithManyNewlines (line 491) | func TestInsertTextWithManyNewlines(t *testing.T) {
  function TestInsertMultipleNewlines (line 528) | func TestInsertMultipleNewlines(t *testing.T) {
  function TestDeleteEmptyText (line 574) | func TestDeleteEmptyText(t *testing.T) {
  function TestDeleteTextFromOneLine (line 603) | func TestDeleteTextFromOneLine(t *testing.T) {
  function TestDeleteTextFromOneLine2 (line 632) | func TestDeleteTextFromOneLine2(t *testing.T) {
  function TestDeleteAllTextFromALine (line 661) | func TestDeleteAllTextFromALine(t *testing.T) {
  function TestDeleteTextFromTwoLines (line 690) | func TestDeleteTextFromTwoLines(t *testing.T) {
  function TestDeleteTextFromManyLines (line 718) | func TestDeleteTextFromManyLines(t *testing.T) {
  function TestDeleteEverything (line 745) | func TestDeleteEverything(t *testing.T) {
  function TestTwoUnrelatedEdits (line 770) | func TestTwoUnrelatedEdits(t *testing.T) {
  function TestTwoEditsOnOneLine (line 806) | func TestTwoEditsOnOneLine(t *testing.T) {
  function TestManyEdits (line 842) | func TestManyEdits(t *testing.T) {
  function TestManyEditsReversed (line 879) | func TestManyEditsReversed(t *testing.T) {
  function TestReplacingNewlines1 (line 916) | func TestReplacingNewlines1(t *testing.T) {
  function TestReplacingNewlines2 (line 953) | func TestReplacingNewlines2(t *testing.T) {
  function TestAdvanced1 (line 1017) | func TestAdvanced1(t *testing.T) {
  function TestAdvancedSimplified (line 1111) | func TestAdvancedSimplified(t *testing.T) {
  function TestIssue144 (line 1149) | func TestIssue144(t *testing.T) {
  function TestIssue2586ReplacingSelectedEndOfLineWithNewlineLocksUpTheDocument (line 1189) | func TestIssue2586ReplacingSelectedEndOfLineWithNewlineLocksUpTheDocumen...
  function TestIssue3980 (line 1213) | func TestIssue3980(t *testing.T) {
  function TestTouchingEditsTwoInsertsAtTheSamePosition (line 1269) | func TestTouchingEditsTwoInsertsAtTheSamePosition(t *testing.T) {
  function TestTouchingEditsInsertAndReplaceTouching (line 1297) | func TestTouchingEditsInsertAndReplaceTouching(t *testing.T) {
  function TestTouchingEditsTwoTouchingReplaces (line 1325) | func TestTouchingEditsTwoTouchingReplaces(t *testing.T) {
  function TestTouchingEditsTwoTouchingDeletes (line 1353) | func TestTouchingEditsTwoTouchingDeletes(t *testing.T) {
  function TestTouchingEditsInsertAndReplace (line 1381) | func TestTouchingEditsInsertAndReplace(t *testing.T) {
  function TestTouchingEditsReplaceAndInsert (line 1409) | func TestTouchingEditsReplaceAndInsert(t *testing.T) {
  function TestSingleDelete1 (line 1437) | func TestSingleDelete1(t *testing.T) {
  function TestSingleDelete2 (line 1458) | func TestSingleDelete2(t *testing.T) {
  function TestSingleDelete3 (line 1479) | func TestSingleDelete3(t *testing.T) {
  function TestSingleDelete4 (line 1500) | func TestSingleDelete4(t *testing.T) {
  function TestSingleDelete5 (line 1521) | func TestSingleDelete5(t *testing.T) {
  function TestMultiDelete6 (line 1542) | func TestMultiDelete6(t *testing.T) {
  function TestMultiDelete7 (line 1565) | func TestMultiDelete7(t *testing.T) {
  function TestMultiDelete8 (line 1588) | func TestMultiDelete8(t *testing.T) {
  function TestMultiDelete9 (line 1611) | func TestMultiDelete9(t *testing.T) {
  function TestSingleInsert1 (line 1634) | func TestSingleInsert1(t *testing.T) {
  function TestSingleInsert2 (line 1655) | func TestSingleInsert2(t *testing.T) {
  function TestSingleInsert3 (line 1676) | func TestSingleInsert3(t *testing.T) {
  function TestSingleInsert4 (line 1697) | func TestSingleInsert4(t *testing.T) {
  function TestSingleInsert5 (line 1718) | func TestSingleInsert5(t *testing.T) {
  function TestMultiInsert6 (line 1739) | func TestMultiInsert6(t *testing.T) {
  function TestMultiInsert7 (line 1761) | func TestMultiInsert7(t *testing.T) {
  function TestMultiInsert8 (line 1783) | func TestMultiInsert8(t *testing.T) {
  function TestMultiInsert9 (line 1805) | func TestMultiInsert9(t *testing.T) {

FILE: internal/buffer/buffer_test.go
  type operation (line 15) | type operation struct
  function init (line 21) | func init() {
  function check (line 29) | func check(t *testing.T, before []string, operations []operation, after ...
  constant maxLineLength (line 99) | maxLineLength = 200
  function randomString (line 103) | func randomString(length int) string {
  function randomText (line 111) | func randomText(nLines int) string {
  function benchCreateAndClose (line 119) | func benchCreateAndClose(testingB *testing.B, nLines int) {
  function benchRead (line 132) | func benchRead(testingB *testing.B, nLines int) {
  function benchEdit (line 152) | func benchEdit(testingB *testing.B, nLines, nCursors int) {
  function BenchmarkCreateAndClose10Lines (line 205) | func BenchmarkCreateAndClose10Lines(b *testing.B) {
  function BenchmarkCreateAndClose100Lines (line 209) | func BenchmarkCreateAndClose100Lines(b *testing.B) {
  function BenchmarkCreateAndClose1000Lines (line 213) | func BenchmarkCreateAndClose1000Lines(b *testing.B) {
  function BenchmarkCreateAndClose10000Lines (line 217) | func BenchmarkCreateAndClose10000Lines(b *testing.B) {
  function BenchmarkCreateAndClose100000Lines (line 221) | func BenchmarkCreateAndClose100000Lines(b *testing.B) {
  function BenchmarkCreateAndClose1000000Lines (line 225) | func BenchmarkCreateAndClose1000000Lines(b *testing.B) {
  function BenchmarkRead10Lines (line 229) | func BenchmarkRead10Lines(b *testing.B) {
  function BenchmarkRead100Lines (line 233) | func BenchmarkRead100Lines(b *testing.B) {
  function BenchmarkRead1000Lines (line 237) | func BenchmarkRead1000Lines(b *testing.B) {
  function BenchmarkRead10000Lines (line 241) | func BenchmarkRead10000Lines(b *testing.B) {
  function BenchmarkRead100000Lines (line 245) | func BenchmarkRead100000Lines(b *testing.B) {
  function BenchmarkRead1000000Lines (line 249) | func BenchmarkRead1000000Lines(b *testing.B) {
  function BenchmarkEdit10Lines1Cursor (line 253) | func BenchmarkEdit10Lines1Cursor(b *testing.B) {
  function BenchmarkEdit100Lines1Cursor (line 257) | func BenchmarkEdit100Lines1Cursor(b *testing.B) {
  function BenchmarkEdit100Lines10Cursors (line 261) | func BenchmarkEdit100Lines10Cursors(b *testing.B) {
  function BenchmarkEdit1000Lines1Cursor (line 265) | func BenchmarkEdit1000Lines1Cursor(b *testing.B) {
  function BenchmarkEdit1000Lines10Cursors (line 269) | func BenchmarkEdit1000Lines10Cursors(b *testing.B) {
  function BenchmarkEdit1000Lines100Cursors (line 273) | func BenchmarkEdit1000Lines100Cursors(b *testing.B) {
  function BenchmarkEdit10000Lines1Cursor (line 277) | func BenchmarkEdit10000Lines1Cursor(b *testing.B) {
  function BenchmarkEdit10000Lines10Cursors (line 281) | func BenchmarkEdit10000Lines10Cursors(b *testing.B) {
  function BenchmarkEdit10000Lines100Cursors (line 285) | func BenchmarkEdit10000Lines100Cursors(b *testing.B) {
  function BenchmarkEdit10000Lines1000Cursors (line 289) | func BenchmarkEdit10000Lines1000Cursors(b *testing.B) {
  function BenchmarkEdit100000Lines1Cursor (line 293) | func BenchmarkEdit100000Lines1Cursor(b *testing.B) {
  function BenchmarkEdit100000Lines10Cursors (line 297) | func BenchmarkEdit100000Lines10Cursors(b *testing.B) {
  function BenchmarkEdit100000Lines100Cursors (line 301) | func BenchmarkEdit100000Lines100Cursors(b *testing.B) {
  function BenchmarkEdit100000Lines1000Cursors (line 305) | func BenchmarkEdit100000Lines1000Cursors(b *testing.B) {
  function BenchmarkEdit1000000Lines1Cursor (line 309) | func BenchmarkEdit1000000Lines1Cursor(b *testing.B) {
  function BenchmarkEdit1000000Lines10Cursors (line 313) | func BenchmarkEdit1000000Lines10Cursors(b *testing.B) {
  function BenchmarkEdit1000000Lines100Cursors (line 317) | func BenchmarkEdit1000000Lines100Cursors(b *testing.B) {
  function BenchmarkEdit1000000Lines1000Cursors (line 321) | func BenchmarkEdit1000000Lines1000Cursors(b *testing.B) {

FILE: internal/buffer/cursor.go
  function InBounds (line 9) | func InBounds(pos Loc, buf *Buffer) bool {
  type Cursor (line 19) | type Cursor struct
    method SetBuf (line 59) | func (c *Cursor) SetBuf(b *Buffer) {
    method Buf (line 63) | func (c *Cursor) Buf() *Buffer {
    method Goto (line 69) | func (c *Cursor) Goto(b Cursor) {
    method GotoLoc (line 77) | func (c *Cursor) GotoLoc(l Loc) {
    method GetVisualX (line 83) | func (c *Cursor) GetVisualX(wrap bool) int {
    method GetCharPosInLine (line 102) | func (c *Cursor) GetCharPosInLine(b []byte, visualPos int) int {
    method Start (line 108) | func (c *Cursor) Start() {
    method StartOfText (line 115) | func (c *Cursor) StartOfText() {
    method IsStartOfText (line 127) | func (c *Cursor) IsStartOfText() bool {
    method End (line 139) | func (c *Cursor) End() {
    method CopySelection (line 146) | func (c *Cursor) CopySelection(target clipboard.Register) {
    method ResetSelection (line 155) | func (c *Cursor) ResetSelection() {
    method SetSelectionStart (line 161) | func (c *Cursor) SetSelectionStart(pos Loc) {
    method SetSelectionEnd (line 166) | func (c *Cursor) SetSelectionEnd(pos Loc) {
    method HasSelection (line 171) | func (c *Cursor) HasSelection() bool {
    method DeleteSelection (line 176) | func (c *Cursor) DeleteSelection() {
    method Deselect (line 191) | func (c *Cursor) Deselect(start bool) {
    method GetSelection (line 204) | func (c *Cursor) GetSelection() []byte {
    method SelectLine (line 215) | func (c *Cursor) SelectLine() {
    method AddLineToSelection (line 229) | func (c *Cursor) AddLineToSelection() {
    method UpN (line 247) | func (c *Cursor) UpN(amount int) {
    method DownN (line 272) | func (c *Cursor) DownN(amount int) {
    method Up (line 277) | func (c *Cursor) Up() {
    method Down (line 282) | func (c *Cursor) Down() {
    method Left (line 288) | func (c *Cursor) Left() {
    method Right (line 303) | func (c *Cursor) Right() {
    method Relocate (line 319) | func (c *Cursor) Relocate() {
    method SelectWord (line 334) | func (c *Cursor) SelectWord() {
    method AddWordToSelection (line 367) | func (c *Cursor) AddWordToSelection() {
    method SelectTo (line 401) | func (c *Cursor) SelectTo(loc Loc) {
    method WordRight (line 412) | func (c *Cursor) WordRight() {
    method WordLeft (line 443) | func (c *Cursor) WordLeft() {
    method SubWordRight (line 477) | func (c *Cursor) SubWordRight() {
    method SubWordLeft (line 537) | func (c *Cursor) SubWordLeft() {
    method RuneUnder (line 603) | func (c *Cursor) RuneUnder(x int) rune {
    method StoreVisualX (line 624) | func (c *Cursor) StoreVisualX() {
  function NewCursor (line 48) | func NewCursor(b *Buffer, l Loc) *Cursor {

FILE: internal/buffer/eventhandler.go
  constant TextEventInsert (line 19) | TextEventInsert = 1
  constant TextEventRemove (line 21) | TextEventRemove = -1
  constant TextEventReplace (line 23) | TextEventReplace = 0
  constant undoThreshold (line 25) | undoThreshold = 1000
  type TextEvent (line 29) | type TextEvent struct
  type Delta (line 38) | type Delta struct
  function ExecuteTextEvent (line 116) | func ExecuteTextEvent(t *TextEvent, buf *SharedBuffer) {
  type EventHandler (line 145) | type EventHandler struct
    method DoTextEvent (line 45) | func (eh *EventHandler) DoTextEvent(t *TextEvent, useUndo bool) {
    method UndoTextEvent (line 139) | func (eh *EventHandler) UndoTextEvent(t *TextEvent) {
    method ApplyDiff (line 167) | func (eh *EventHandler) ApplyDiff(new string) {
    method Insert (line 184) | func (eh *EventHandler) Insert(start Loc, textStr string) {
    method InsertBytes (line 190) | func (eh *EventHandler) InsertBytes(start Loc, text []byte) {
    method Remove (line 205) | func (eh *EventHandler) Remove(start, end Loc) {
    method MultipleReplace (line 221) | func (eh *EventHandler) MultipleReplace(deltas []Delta) {
    method Replace (line 232) | func (eh *EventHandler) Replace(start, end Loc, replace string) {
    method Execute (line 238) | func (eh *EventHandler) Execute(t *TextEvent) {
    method Undo (line 257) | func (eh *EventHandler) Undo() bool {
    method UndoOneEvent (line 282) | func (eh *EventHandler) UndoOneEvent() {
    method Redo (line 304) | func (eh *EventHandler) Redo() bool {
    method RedoOneEvent (line 329) | func (eh *EventHandler) RedoOneEvent() {
    method updateTrailingWs (line 347) | func (eh *EventHandler) updateTrailingWs(t *TextEvent) {
  function NewEventHandler (line 154) | func NewEventHandler(buf *SharedBuffer, cursors []*Cursor) *EventHandler {

FILE: internal/buffer/line_array.go
  function runeToByteIndex (line 14) | func runeToByteIndex(n int, txt []byte) int {
  type searchState (line 36) | type searchState struct
  type Line (line 46) | type Line struct
  constant FFAuto (line 64) | FFAuto = 0
  constant FFUnix (line 65) | FFUnix = 1
  constant FFDos (line 66) | FFDos  = 2
  type FileFormat (line 69) | type FileFormat
  type LineArray (line 73) | type LineArray struct
    method Bytes (line 172) | func (la *LineArray) Bytes() []byte {
    method newlineBelow (line 189) | func (la *LineArray) newlineBelow(y int) {
    method insert (line 204) | func (la *LineArray) insert(pos Loc, value []byte) {
    method insertByte (line 227) | func (la *LineArray) insertByte(pos Loc, value byte) {
    method joinLines (line 234) | func (la *LineArray) joinLines(a, b int) {
    method split (line 240) | func (la *LineArray) split(pos Loc) {
    method remove (line 251) | func (la *LineArray) remove(start, end Loc) []byte {
    method deleteToEnd (line 270) | func (la *LineArray) deleteToEnd(pos Loc) {
    method deleteFromStart (line 275) | func (la *LineArray) deleteFromStart(pos Loc) {
    method deleteLine (line 280) | func (la *LineArray) deleteLine(y int) {
    method deleteLines (line 284) | func (la *LineArray) deleteLines(y1, y2 int) {
    method Substr (line 289) | func (la *LineArray) Substr(start, end Loc) []byte {
    method LinesNum (line 310) | func (la *LineArray) LinesNum() int {
    method Start (line 315) | func (la *LineArray) Start() Loc {
    method End (line 320) | func (la *LineArray) End() Loc {
    method LineBytes (line 326) | func (la *LineArray) LineBytes(lineN int) []byte {
    method State (line 334) | func (la *LineArray) State(lineN int) highlight.State {
    method SetState (line 341) | func (la *LineArray) SetState(lineN int, s highlight.State) {
    method SetMatch (line 348) | func (la *LineArray) SetMatch(lineN int, m highlight.LineMatch) {
    method Match (line 355) | func (la *LineArray) Match(lineN int) highlight.LineMatch {
    method Lock (line 362) | func (la *LineArray) Lock() {
    method Unlock (line 367) | func (la *LineArray) Unlock() {
    method SearchMatch (line 383) | func (la *LineArray) SearchMatch(b *Buffer, pos Loc) bool {
    method invalidateSearchMatches (line 439) | func (la *LineArray) invalidateSearchMatches(lineN int) {
  function Append (line 83) | func Append(slice []Line, data ...Line) []Line {
  function NewLineArray (line 98) | func NewLineArray(size uint64, endings FileFormat, reader io.Reader) *Li...

FILE: internal/buffer/line_array_test.go
  function init (line 18) | func init() {
  function TestSplit (line 23) | func TestSplit(t *testing.T) {
  function TestJoin (line 33) | func TestJoin(t *testing.T) {
  function TestInsert (line 43) | func TestInsert(t *testing.T) {
  function TestRemove (line 55) | func TestRemove(t *testing.T) {

FILE: internal/buffer/loc.go
  type Loc (line 8) | type Loc struct
    method LessThan (line 13) | func (l Loc) LessThan(b Loc) bool {
    method GreaterThan (line 21) | func (l Loc) GreaterThan(b Loc) bool {
    method GreaterEqual (line 29) | func (l Loc) GreaterEqual(b Loc) bool {
    method LessEqual (line 40) | func (l Loc) LessEqual(b Loc) bool {
    method Clamp (line 51) | func (l Loc) Clamp(start, end Loc) Loc {
    method right (line 86) | func (l Loc) right(buf *LineArray) Loc {
    method left (line 100) | func (l Loc) left(buf *LineArray) Loc {
    method MoveLA (line 115) | func (l Loc) MoveLA(n int, buf *LineArray) Loc {
    method Diff (line 129) | func (l Loc) Diff(b Loc, buf *Buffer) int {
    method Move (line 134) | func (l Loc) Move(n int, buf *Buffer) Loc {
  function DiffLA (line 63) | func DiffLA(a, b Loc, buf *LineArray) int {
  function ByteOffset (line 139) | func ByteOffset(pos Loc, buf *Buffer) int {
  function clamp (line 151) | func clamp(pos Loc, la *LineArray) Loc {

FILE: internal/buffer/message.go
  type MsgType (line 8) | type MsgType
  constant MTInfo (line 11) | MTInfo = iota
  constant MTWarning (line 12) | MTWarning
  constant MTError (line 13) | MTError
  type Message (line 17) | type Message struct
    method Style (line 46) | func (m *Message) Style() tcell.Style {
  function NewMessage (line 29) | func NewMessage(owner string, msg string, start, end Loc, kind MsgType) ...
  function NewMessageAtLine (line 40) | func NewMessageAtLine(owner string, msg string, line int, kind MsgType) ...
  method AddMessage (line 64) | func (b *Buffer) AddMessage(m *Message) {
  method removeMsg (line 68) | func (b *Buffer) removeMsg(i int) {
  method ClearMessages (line 74) | func (b *Buffer) ClearMessages(owner string) {
  method ClearAllMessages (line 82) | func (b *Buffer) ClearAllMessages() {
  type Messager (line 86) | type Messager interface
  function SetMessager (line 92) | func SetMessager(m Messager) {

FILE: internal/buffer/save.go
  constant LargeFileThreshold (line 25) | LargeFileThreshold = 50000
  type wrappedFile (line 27) | type wrappedFile struct
    method Truncate (line 124) | func (wf wrappedFile) Truncate() error {
    method Write (line 135) | func (wf wrappedFile) Write(b *SharedBuffer) (int, error) {
    method Close (line 183) | func (wf wrappedFile) Close() error {
  type saveResponse (line 36) | type saveResponse struct
  type saveRequest (line 41) | type saveRequest struct
  function init (line 52) | func init() {
  function openFile (line 77) | func openFile(name string, withSudo bool) (wrappedFile, error) {
  method overwriteFile (line 200) | func (b *SharedBuffer) overwriteFile(name string) (int, error) {
  method Save (line 216) | func (b *Buffer) Save() error {
  method AutoSave (line 221) | func (b *Buffer) AutoSave() error {
  method SaveAs (line 229) | func (b *Buffer) SaveAs(filename string) error {
  method SaveWithSudo (line 233) | func (b *Buffer) SaveWithSudo() error {
  method SaveAsWithSudo (line 237) | func (b *Buffer) SaveAsWithSudo(filename string) error {
  method saveToFile (line 241) | func (b *Buffer) saveToFile(filename string, withSudo bool, autoSave boo...
  method safeWrite (line 356) | func (b *SharedBuffer) safeWrite(path string, withSudo bool, newFile boo...

FILE: internal/buffer/search.go
  constant padStart (line 16) | padStart = 1 << iota
  constant padEnd (line 17) | padEnd
  function findLineParams (line 20) | func findLineParams(b *Buffer, start, end Loc, i int, r *regexp.Regexp) ...
  method findDown (line 64) | func (b *Buffer) findDown(r *regexp.Regexp, start, end Loc) ([2]Loc, boo...
  method findUp (line 101) | func (b *Buffer) findUp(r *regexp.Regexp, start, end Loc) ([2]Loc, bool) {
  method findAll (line 130) | func (b *Buffer) findAll(r *regexp.Regexp, start, end Loc) [][2]Loc {
  method FindNext (line 154) | func (b *Buffer) FindNext(s string, start, end, from Loc, down bool, use...
  method ReplaceRegex (line 195) | func (b *Buffer) ReplaceRegex(start, end Loc, search *regexp.Regexp, rep...

FILE: internal/buffer/serialize.go
  type SerializedBuffer (line 17) | type SerializedBuffer struct
  method Serialize (line 24) | func (b *Buffer) Serialize() error {
  method Unserialize (line 63) | func (b *Buffer) Unserialize() error {

FILE: internal/buffer/settings.go
  method ReloadSettings (line 15) | func (b *Buffer) ReloadSettings(reloadFiletype bool) {
  method DoSetOptionNative (line 62) | func (b *Buffer) DoSetOptionNative(option string, nativeValue any) {
  method SetOptionNative (line 141) | func (b *Buffer) SetOptionNative(option string, nativeValue any) error {
  method SetOption (line 153) | func (b *Buffer) SetOption(option, value string) error {
  method doCallbacks (line 166) | func (b *Buffer) doCallbacks(option string, oldValue any, newValue any) {

FILE: internal/buffer/stack.go
  type TEStack (line 4) | type TEStack struct
    method Len (line 16) | func (s *TEStack) Len() int {
    method Push (line 21) | func (s *TEStack) Push(value *TextEvent) {
    method Pop (line 28) | func (s *TEStack) Pop() (value *TextEvent) {
    method Peek (line 38) | func (s *TEStack) Peek() *TextEvent {
  type Element (line 10) | type Element struct

FILE: internal/buffer/stack_test.go
  function TestStack (line 10) | func TestStack(t *testing.T) {

FILE: internal/clipboard/clipboard.go
  type Method (line 9) | type Method
  constant External (line 15) | External Method = iota
  constant Terminal (line 18) | Terminal
  constant Internal (line 21) | Internal
  type Register (line 29) | type Register
  constant ClipboardReg (line 33) | ClipboardReg Register = -1
  constant PrimaryReg (line 35) | PrimaryReg = -2
  function Initialize (line 41) | func Initialize(m Method) error {
  function SetMethod (line 59) | func SetMethod(m string) Method {
  function Read (line 72) | func Read(r Register) (string, error) {
  function Write (line 77) | func Write(text string, r Register) error {
  function ReadMulti (line 82) | func ReadMulti(r Register, num, ncursors int) (string, error) {
  function WriteMulti (line 94) | func WriteMulti(text string, r Register, num int, ncursors int) error {
  function ValidMulti (line 100) | func ValidMulti(r Register, clip string, ncursors int) bool {
  function writeMulti (line 104) | func writeMulti(text string, r Register, num int, ncursors int, m Method...
  function read (line 109) | func read(r Register, m Method) (string, error) {
  function write (line 139) | func write(text string, r Register, m Method) error {

FILE: internal/clipboard/internal.go
  type internalClipboard (line 3) | type internalClipboard
    method read (line 11) | func (c internalClipboard) read(r Register) string {
    method write (line 15) | func (c internalClipboard) write(text string, r Register) {
  function init (line 7) | func init() {

FILE: internal/clipboard/multi.go
  type multiClipboard (line 8) | type multiClipboard
    method getAllText (line 12) | func (c multiClipboard) getAllText(r Register) string {
    method getText (line 25) | func (c multiClipboard) getText(r Register, num int) string {
    method isValid (line 38) | func (c multiClipboard) isValid(r Register, clipboard string, ncursors...
    method writeText (line 47) | func (c multiClipboard) writeText(text string, r Register, num int, nc...
  function init (line 61) | func init() {

FILE: internal/clipboard/terminal.go
  type terminalClipboard (line 11) | type terminalClipboard struct
    method read (line 15) | func (t terminalClipboard) read(reg string) (string, error) {
    method write (line 31) | func (t terminalClipboard) write(text, reg string) error {

FILE: internal/config/autosave.go
  function init (line 10) | func init() {
  function SetAutoTime (line 15) | func SetAutoTime(a float64) {
  function StartAutoSave (line 19) | func StartAutoSave() {

FILE: internal/config/colorscheme.go
  function GetColor (line 19) | func GetColor(color string) tcell.Style {
  function ColorschemeExists (line 46) | func ColorschemeExists(colorschemeName string) bool {
  function InitColorscheme (line 51) | func InitColorscheme() error {
  function LoadDefaultColorscheme (line 72) | func LoadDefaultColorscheme() (map[string]tcell.Style, error) {
  function LoadColorscheme (line 78) | func LoadColorscheme(colorschemeName string, parsedColorschemes *[]strin...
  function ParseColorscheme (line 100) | func ParseColorscheme(name string, text string, parsedColorschemes *[]st...
  function StringToStyle (line 164) | func StringToStyle(str string) tcell.Style {
  function StringToColor (line 213) | func StringToColor(str string) (tcell.Color, bool) {
  function GetColor256 (line 263) | func GetColor256(color int) tcell.Color {

FILE: internal/config/colorscheme_test.go
  function TestSimpleStringToStyle (line 10) | func TestSimpleStringToStyle(t *testing.T) {
  function TestAttributeStringToStyle (line 19) | func TestAttributeStringToStyle(t *testing.T) {
  function TestMultiAttributesStringToStyle (line 29) | func TestMultiAttributesStringToStyle(t *testing.T) {
  function TestColor256StringToStyle (line 41) | func TestColor256StringToStyle(t *testing.T) {
  function TestColorHexStringToStyle (line 50) | func TestColorHexStringToStyle(t *testing.T) {
  function TestColorschemeParser (line 59) | func TestColorschemeParser(t *testing.T) {

FILE: internal/config/config.go
  function InitConfigDir (line 15) | func InitConfigDir(flagConfigDir string) error {

FILE: internal/config/globals.go
  constant DoubleClickThreshold (line 4) | DoubleClickThreshold = 400
  function init (line 9) | func init() {

FILE: internal/config/plugin.go
  function LoadAllPlugins (line 15) | func LoadAllPlugins() error {
  function RunPluginFn (line 28) | func RunPluginFn(fn string, args ...lua.LValue) error {
  function RunPluginFnBool (line 45) | func RunPluginFnBool(settings map[string]any, fn string, args ...lua.LVa...
  type Plugin (line 68) | type Plugin struct
    method IsLoaded (line 78) | func (p *Plugin) IsLoaded() bool {
    method Load (line 89) | func (p *Plugin) Load() error {
    method Call (line 109) | func (p *Plugin) Call(fn string, args ...lua.LValue) (lua.LValue, erro...
  function FindPlugin (line 133) | func FindPlugin(name string) *Plugin {

FILE: internal/config/plugin_installer.go
  constant CorePluginName (line 27) | CorePluginName = "micro"
  type PluginChannel (line 30) | type PluginChannel
    method Fetch (line 131) | func (pc PluginChannel) Fetch(out io.Writer) PluginPackages {
  type PluginChannels (line 33) | type PluginChannels
    method Fetch (line 124) | func (pc PluginChannels) Fetch(out io.Writer) PluginPackages {
  type PluginRepository (line 36) | type PluginRepository
    method Fetch (line 151) | func (pr PluginRepository) Fetch(out io.Writer) PluginPackages {
  type PluginPackage (line 39) | type PluginPackage struct
    method String (line 75) | func (pp *PluginPackage) String() string {
    method UnmarshalJSON (line 201) | func (pp *PluginPackage) UnmarshalJSON(data []byte) error {
    method Match (line 288) | func (pp PluginPackage) Match(text string) bool {
    method IsInstallable (line 307) | func (pp PluginPackage) IsInstallable(out io.Writer) error {
    method Install (line 594) | func (pl PluginPackage) Install(out io.Writer) {
  type PluginPackages (line 49) | type PluginPackages
    method Get (line 473) | func (pl PluginPackages) Get(name string) *PluginPackage {
    method GetAllVersions (line 482) | func (pl PluginPackages) GetAllVersions(name string) PluginVersions {
    method Resolve (line 515) | func (all PluginPackages) Resolve(selectedVersions PluginVersions, ope...
  type PluginVersion (line 52) | type PluginVersion struct
    method Pack (line 59) | func (pv *PluginVersion) Pack() *PluginPackage {
    method UnmarshalJSON (line 173) | func (pv *PluginVersion) UnmarshalJSON(data []byte) error {
    method DownloadAndInstall (line 396) | func (pv *PluginVersion) DownloadAndInstall(out io.Writer) error {
  type PluginVersions (line 64) | type PluginVersions
    method find (line 263) | func (pv PluginVersions) find(ppName string) *PluginVersion {
    method Len (line 273) | func (pv PluginVersions) Len() int {
    method Swap (line 278) | func (pv PluginVersions) Swap(i, j int) {
    method Less (line 283) | func (pv PluginVersions) Less(i, j int) bool {
    method install (line 544) | func (pv PluginVersions) install(out io.Writer) {
  type PluginDependency (line 67) | type PluginDependency struct
  type PluginDependencies (line 73) | type PluginDependencies
    method Join (line 491) | func (req PluginDependencies) Join(other PluginDependencies) PluginDep...
  function fetchAllSources (line 95) | func fetchAllSources(count int, fetcher func(i int) PluginPackages) Plug...
  function GetAllPluginPackages (line 224) | func GetAllPluginPackages(out io.Writer) PluginPackages {
  function SearchPlugin (line 318) | func SearchPlugin(out io.Writer, texts []string) (plugins PluginPackages) {
  function isUnknownCoreVersion (line 336) | func isUnknownCoreVersion() bool {
  function newStaticPluginVersion (line 341) | func newStaticPluginVersion(name, version string, builtin bool) *PluginV...
  function GetInstalledVersions (line 363) | func GetInstalledVersions(withCore bool) PluginVersions {
  function GetInstalledPluginVersion (line 383) | func GetInstalledPluginVersion(name string) string {
  function UninstallPlugin (line 577) | func UninstallPlugin(out io.Writer, name string) {
  function UpdatePlugins (line 608) | func UpdatePlugins(out io.Writer, plugins []string) {
  function PluginCommand (line 644) | func PluginCommand(out io.Writer, cmd string, args []string) {

FILE: internal/config/plugin_installer_test.go
  function TestDependencyResolving (line 11) | func TestDependencyResolving(t *testing.T) {

FILE: internal/config/plugin_manager.go
  type PluginInfo (line 26) | type PluginInfo struct
  function NewPluginInfo (line 35) | func NewPluginInfo(data []byte) (*PluginInfo, error) {

FILE: internal/config/rtfiles.go
  constant RTColorscheme (line 15) | RTColorscheme  = 0
  constant RTSyntax (line 16) | RTSyntax       = 1
  constant RTHelp (line 17) | RTHelp         = 2
  constant RTPlugin (line 18) | RTPlugin       = 3
  constant RTSyntaxHeader (line 19) | RTSyntaxHeader = 4
  type RTFiletype (line 26) | type RTFiletype
  type RuntimeFile (line 29) | type RuntimeFile interface
  function init (line 40) | func init() {
  function initRuntimeVars (line 44) | func initRuntimeVars() {
  function NewRTFiletype (line 50) | func NewRTFiletype() int {
  type realFile (line 58) | type realFile
    method Name (line 76) | func (rf realFile) Name() string {
    method Data (line 81) | func (rf realFile) Data() ([]byte, error) {
  type assetFile (line 61) | type assetFile
    method Name (line 85) | func (af assetFile) Name() string {
    method Data (line 90) | func (af assetFile) Data() ([]byte, error) {
  type memoryFile (line 64) | type memoryFile struct
    method Name (line 69) | func (mf memoryFile) Name() string {
    method Data (line 72) | func (mf memoryFile) Data() ([]byte, error) {
  function AddRuntimeFile (line 95) | func AddRuntimeFile(fileType RTFiletype, file RuntimeFile) {
  function AddRealRuntimeFile (line 100) | func AddRealRuntimeFile(fileType RTFiletype, file RuntimeFile) {
  function AddRuntimeFilesFromDirectory (line 107) | func AddRuntimeFilesFromDirectory(fileType RTFiletype, directory, patter...
  function AddRuntimeFilesFromAssets (line 119) | func AddRuntimeFilesFromAssets(fileType RTFiletype, directory, pattern s...
  function FindRuntimeFile (line 141) | func FindRuntimeFile(fileType RTFiletype, name string) RuntimeFile {
  function ListRuntimeFiles (line 151) | func ListRuntimeFiles(fileType RTFiletype) []RuntimeFile {
  function ListRealRuntimeFiles (line 157) | func ListRealRuntimeFiles(fileType RTFiletype) []RuntimeFile {
  function InitRuntimeFiles (line 164) | func InitRuntimeFiles(user bool) {
  function InitPlugins (line 181) | func InitPlugins() {
  function PluginReadRuntimeFile (line 273) | func PluginReadRuntimeFile(fileType RTFiletype, name string) string {
  function PluginListRuntimeFiles (line 283) | func PluginListRuntimeFiles(fileType RTFiletype) []string {
  function PluginAddRuntimeFile (line 293) | func PluginAddRuntimeFile(plugin string, filetype RTFiletype, filePath s...
  function PluginAddRuntimeFilesFromDirectory (line 310) | func PluginAddRuntimeFilesFromDirectory(plugin string, filetype RTFilety...
  function PluginAddRuntimeFileFromMemory (line 327) | func PluginAddRuntimeFileFromMemory(filetype RTFiletype, filename, data ...

FILE: internal/config/rtfiles_test.go
  function init (line 9) | func init() {
  function TestAddFile (line 13) | func TestAddFile(t *testing.T) {
  function TestFindFile (line 32) | func TestFindFile(t *testing.T) {

FILE: internal/config/settings.go
  type optionValidator (line 20) | type optionValidator
  function writeFile (line 164) | func writeFile(name string, txt []byte) error {
  function init (line 168) | func init() {
  function validateParsedSettings (line 173) | func validateParsedSettings() error {
  function ReadSettings (line 231) | func ReadSettings() error {
  function ParsedSettings (line 256) | func ParsedSettings() map[string]any {
  function verifySetting (line 264) | func verifySetting(option string, value any, def any) error {
  function InitGlobalSettings (line 295) | func InitGlobalSettings() error {
  function UpdatePathGlobLocals (line 310) | func UpdatePathGlobLocals(settings map[string]any, path string) {
  function UpdateFileTypeLocals (line 326) | func UpdateFileTypeLocals(settings map[string]any, filetype string) {
  function WriteSettings (line 341) | func WriteSettings(filename string) error {
  function OverwriteSettings (line 383) | func OverwriteSettings(filename string) error {
  function RegisterCommonOptionPlug (line 405) | func RegisterCommonOptionPlug(pl string, name string, defaultvalue any) ...
  function RegisterGlobalOptionPlug (line 410) | func RegisterGlobalOptionPlug(pl string, name string, defaultvalue any) ...
  function RegisterCommonOption (line 415) | func RegisterCommonOption(name string, defaultvalue any) error {
  function RegisterGlobalOption (line 424) | func RegisterGlobalOption(name string, defaultvalue any) error {
  function GetGlobalOption (line 433) | func GetGlobalOption(name string) any {
  function defaultFileFormat (line 437) | func defaultFileFormat() string {
  function defaultFakeCursor (line 444) | func defaultFakeCursor() bool {
  function GetInfoBarOffset (line 453) | func GetInfoBarOffset() int {
  function DefaultCommonSettings (line 466) | func DefaultCommonSettings() map[string]any {
  function DefaultAllSettings (line 476) | func DefaultAllSettings() map[string]any {
  function GetNativeValue (line 488) | func GetNativeValue(option, value string) (any, error) {
  function OptionIsValid (line 515) | func OptionIsValid(option string, value any) error {
  function validatePositiveValue (line 525) | func validatePositiveValue(option string, value any) error {
  function validateNonNegativeValue (line 539) | func validateNonNegativeValue(option string, value any) error {
  function validateChoice (line 553) | func validateChoice(option string, value any) error {
  function validateColorscheme (line 573) | func validateColorscheme(option string, value any) error {
  function validateEncoding (line 587) | func validateEncoding(option string, value any) error {

FILE: internal/display/bufwindow.go
  type BufWindow (line 16) | type BufWindow struct
    method SetBuffer (line 48) | func (w *BufWindow) SetBuffer(b *buffer.Buffer) {
    method GetView (line 78) | func (w *BufWindow) GetView() *View {
    method SetView (line 83) | func (w *BufWindow) SetView(view *View) {
    method Resize (line 88) | func (w *BufWindow) Resize(width, height int) {
    method SetActive (line 96) | func (w *BufWindow) SetActive(b bool) {
    method IsActive (line 101) | func (w *BufWindow) IsActive() bool {
    method BufView (line 108) | func (w *BufWindow) BufView() View {
    method updateDisplayInfo (line 119) | func (w *BufWindow) updateDisplayInfo() {
    method getStartInfo (line 175) | func (w *BufWindow) getStartInfo(n, lineN int) ([]byte, int, int, *tce...
    method Clear (line 209) | func (w *BufWindow) Clear() {
    method Relocate (line 220) | func (w *BufWindow) Relocate() bool {
    method LocFromVisual (line 270) | func (w *BufWindow) LocFromVisual(svloc buffer.Loc) buffer.Loc {
    method drawGutter (line 282) | func (w *BufWindow) drawGutter(vloc *buffer.Loc, bloc *buffer.Loc) {
    method drawDiffGutter (line 298) | func (w *BufWindow) drawDiffGutter(backgroundStyle tcell.Style, softwr...
    method drawLineNum (line 330) | func (w *BufWindow) drawLineNum(lineNumStyle tcell.Style, softwrapped ...
    method getStyle (line 364) | func (w *BufWindow) getStyle(style tcell.Style, bloc buffer.Loc) (tcel...
    method showCursor (line 372) | func (w *BufWindow) showCursor(x, y int, main bool) {
    method displayBuffer (line 383) | func (w *BufWindow) displayBuffer() {
    method displayStatusLine (line 842) | func (w *BufWindow) displayStatusLine() {
    method displayScrollBar (line 870) | func (w *BufWindow) displayScrollBar() {
    method Display (line 897) | func (w *BufWindow) Display() {
  function NewBufWindow (line 35) | func NewBufWindow(x, y, width, height int, buf *buffer.Buffer) *BufWindow {

FILE: internal/display/infowindow.go
  type InfoWindow (line 13) | type InfoWindow struct
    method errStyle (line 20) | func (i *InfoWindow) errStyle() tcell.Style {
    method defStyle (line 32) | func (i *InfoWindow) defStyle() tcell.Style {
    method Resize (line 53) | func (i *InfoWindow) Resize(w, h int) {
    method SetBuffer (line 58) | func (i *InfoWindow) SetBuffer(b *buffer.Buffer) {
    method Relocate (line 62) | func (i *InfoWindow) Relocate() bool   { return false }
    method GetView (line 63) | func (i *InfoWindow) GetView() *View   { return i.View }
    method SetView (line 64) | func (i *InfoWindow) SetView(v *View)  {}
    method SetActive (line 65) | func (i *InfoWindow) SetActive(b bool) {}
    method IsActive (line 66) | func (i *InfoWindow) IsActive() bool   { return true }
    method LocFromVisual (line 68) | func (i *InfoWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc {
    method BufView (line 75) | func (i *InfoWindow) BufView() View {
    method Scroll (line 86) | func (i *InfoWindow) Scroll(s SLoc, n int) SLoc        { return s }
    method Diff (line 87) | func (i *InfoWindow) Diff(s1, s2 SLoc) int             { return 0 }
    method SLocFromLoc (line 88) | func (i *InfoWindow) SLocFromLoc(loc buffer.Loc) SLoc  { return SLoc{0...
    method VLocFromLoc (line 89) | func (i *InfoWindow) VLocFromLoc(loc buffer.Loc) VLoc  { return VLoc{S...
    method LocFromVLoc (line 90) | func (i *InfoWindow) LocFromVLoc(vloc VLoc) buffer.Loc { return buffer...
    method Clear (line 92) | func (i *InfoWindow) Clear() {
    method displayBuffer (line 98) | func (i *InfoWindow) displayBuffer() {
    method displayKeyMenu (line 168) | func (i *InfoWindow) displayKeyMenu() {
    method totalSize (line 182) | func (i *InfoWindow) totalSize() int {
    method scrollToSuggestion (line 190) | func (i *InfoWindow) scrollToSuggestion() {
    method Display (line 212) | func (i *InfoWindow) Display() {
  function NewInfoWindow (line 42) | func NewInfoWindow(b *info.InfoBuf) *InfoWindow {

FILE: internal/display/softwrap.go
  type SLoc (line 13) | type SLoc struct
    method LessThan (line 18) | func (s SLoc) LessThan(b SLoc) bool {
    method GreaterThan (line 26) | func (s SLoc) GreaterThan(b SLoc) bool {
    method LessEqual (line 34) | func (s SLoc) LessEqual(b SLoc) bool {
    method GreaterEqual (line 45) | func (s SLoc) GreaterEqual(b SLoc) bool {
  type VLoc (line 57) | type VLoc struct
  type SoftWrap (line 62) | type SoftWrap interface
  method getVLocFromLoc (line 70) | func (w *BufWindow) getVLocFromLoc(loc buffer.Loc) VLoc {
  method getLocFromVLoc (line 145) | func (w *BufWindow) getLocFromVLoc(svloc VLoc) buffer.Loc {
  method getRowCount (line 226) | func (w *BufWindow) getRowCount(line int) int {
  method scrollUp (line 231) | func (w *BufWindow) scrollUp(s SLoc, n int) SLoc {
  method scrollDown (line 248) | func (w *BufWindow) scrollDown(s SLoc, n int) SLoc {
  method scroll (line 266) | func (w *BufWindow) scroll(s SLoc, n int) SLoc {
  method diff (line 273) | func (w *BufWindow) diff(s1, s2 SLoc) int {
  method Scroll (line 292) | func (w *BufWindow) Scroll(s SLoc, n int) SLoc {
  method Diff (line 301) | func (w *BufWindow) Diff(s1, s2 SLoc) int {
  method SLocFromLoc (line 313) | func (w *BufWindow) SLocFromLoc(loc buffer.Loc) SLoc {
  method VLocFromLoc (line 322) | func (w *BufWindow) VLocFromLoc(loc buffer.Loc) VLoc {
  method LocFromVLoc (line 334) | func (w *BufWindow) LocFromVLoc(vloc VLoc) buffer.Loc {

FILE: internal/display/statusline.go
  type StatusLine (line 25) | type StatusLine struct
    method FindOpt (line 99) | func (s *StatusLine) FindOpt(opt string) any {
    method Display (line 109) | func (s *StatusLine) Display() {
  function SetStatusInfoFnLua (line 64) | func SetStatusInfoFnLua(fn string) {
  function NewStatusLine (line 92) | func NewStatusLine(win *BufWindow) *StatusLine {

FILE: internal/display/tabwindow.go
  type TabWindow (line 12) | type TabWindow struct
    method Resize (line 27) | func (w *TabWindow) Resize(width, height int) {
    method LocFromVisual (line 31) | func (w *TabWindow) LocFromVisual(vloc buffer.Loc) int {
    method Scroll (line 49) | func (w *TabWindow) Scroll(amt int) {
    method TotalSize (line 59) | func (w *TabWindow) TotalSize() int {
    method Active (line 67) | func (w *TabWindow) Active() int {
    method SetActive (line 71) | func (w *TabWindow) SetActive(a int) {
    method Display (line 94) | func (w *TabWindow) Display() {
  function NewTabWindow (line 20) | func NewTabWindow(w int, y int) *TabWindow {

FILE: internal/display/termwindow.go
  type TermWindow (line 13) | type TermWindow struct
    method Resize (line 30) | func (w *TermWindow) Resize(width, height int) {
    method SetActive (line 38) | func (w *TermWindow) SetActive(b bool) {
    method IsActive (line 42) | func (w *TermWindow) IsActive() bool {
    method LocFromVisual (line 46) | func (w *TermWindow) LocFromVisual(vloc buffer.Loc) buffer.Loc {
    method Clear (line 50) | func (w *TermWindow) Clear() {
    method Relocate (line 58) | func (w *TermWindow) Relocate() bool { return true }
    method GetView (line 59) | func (w *TermWindow) GetView() *View {
    method SetView (line 62) | func (w *TermWindow) SetView(v *View) {
    method Display (line 67) | func (w *TermWindow) Display() {
  function NewTermWindow (line 20) | func NewTermWindow(x, y, w, h int, term *shell.Terminal) *TermWindow {

FILE: internal/display/uiwindow.go
  type UIWindow (line 11) | type UIWindow struct
    method drawNode (line 21) | func (w *UIWindow) drawNode(n *views.Node) {
    method Display (line 52) | func (w *UIWindow) Display() {
    method GetMouseSplitNode (line 56) | func (w *UIWindow) GetMouseSplitNode(vloc buffer.Loc) *views.Node {
    method Resize (line 85) | func (w *UIWindow) Resize(width, height int) {}
    method SetActive (line 86) | func (w *UIWindow) SetActive(b bool)         {}
  function NewUIWindow (line 15) | func NewUIWindow(n *views.Node) *UIWindow {

FILE: internal/display/window.go
  type View (line 7) | type View struct
  type Window (line 20) | type Window interface
  type BWindow (line 32) | type BWindow interface

FILE: internal/info/gutter.go
  type GutterMessage (line 4) | type GutterMessage struct
  constant GutterInfo (line 13) | GutterInfo = iota
  constant GutterWarning (line 15) | GutterWarning
  constant GutterError (line 17) | GutterError

FILE: internal/info/history.go
  method LoadHistory (line 20) | func (i *InfoBuf) LoadHistory() {
  method SaveHistory (line 46) | func (i *InfoBuf) SaveHistory() {
  method AddToHistory (line 74) | func (i *InfoBuf) AddToHistory(ptype string, item string) {
  method UpHistory (line 96) | func (i *InfoBuf) UpHistory(history []string) {
  method DownHistory (line 105) | func (i *InfoBuf) DownHistory(history []string) {
  method SearchUpHistory (line 115) | func (i *InfoBuf) SearchUpHistory(history []string) {
  method SearchDownHistory (line 123) | func (i *InfoBuf) SearchDownHistory(history []string) {
  method searchHistory (line 129) | func (i *InfoBuf) searchHistory(history []string, down bool) {

FILE: internal/info/infobuffer.go
  type InfoBuf (line 11) | type InfoBuf struct
    method Close (line 53) | func (i *InfoBuf) Close() {
    method Message (line 58) | func (i *InfoBuf) Message(msg ...any) {
    method GutterMessage (line 70) | func (i *InfoBuf) GutterMessage(msg ...any) {
    method ClearGutter (line 76) | func (i *InfoBuf) ClearGutter() {
    method Error (line 82) | func (i *InfoBuf) Error(msg ...any) {
    method Prompt (line 97) | func (i *InfoBuf) Prompt(prompt string, msg string, ptype string, even...
    method YNPrompt (line 123) | func (i *InfoBuf) YNPrompt(prompt string, donecb func(bool, bool)) {
    method DonePrompt (line 137) | func (i *InfoBuf) DonePrompt(canceled bool) {
    method Reset (line 174) | func (i *InfoBuf) Reset() {
  function NewBuffer (line 42) | func NewBuffer() *InfoBuf {

FILE: internal/lua/lua.go
  function LoadFile (line 31) | func LoadFile(module string, file string, data []byte) error {
  function Import (line 43) | func Import(pkg string) *lua.LTable {
  function importFmt (line 86) | func importFmt() *lua.LTable {
  function importIo (line 112) | func importIo() *lua.LTable {
  function importIoUtil (line 137) | func importIoUtil() *lua.LTable {
  function importNet (line 148) | func importNet() *lua.LTable {
  function importMath (line 216) | func importMath() *lua.LTable {
  function importMathRand (line 284) | func importMathRand() *lua.LTable {
  function importOs (line 304) | func importOs() *lua.LTable {
  function importRuntime (line 399) | func importRuntime() *lua.LTable {
  function importPath (line 411) | func importPath() *lua.LTable {
  function importFilePath (line 427) | func importFilePath() *lua.LTable {
  function importStrings (line 451) | func importStrings() *lua.LTable {
  function importRegexp (line 501) | func importRegexp() *lua.LTable {
  function importErrors (line 516) | func importErrors() *lua.LTable {
  function importTime (line 524) | func importTime() *lua.LTable {
  function importUtf8 (line 556) | func importUtf8() *lua.LTable {
  function importHumanize (line 577) | func importHumanize() *lua.LTable {
  function importHTTP (line 586) | func importHTTP() *lua.LTable {
  function importArchiveZip (line 595) | func importArchiveZip() *lua.LTable {

FILE: internal/screen/message.go
  function TermMessage (line 17) | func TermMessage(msg ...any) {
  function TermPrompt (line 34) | func TermPrompt(prompt string, options []string, wait bool) int {
  function TermError (line 63) | func TermError(filename string, lineNum int, err string) {

FILE: internal/screen/screen.go
  function Lock (line 42) | func Lock() {
  function Unlock (line 47) | func Unlock() {
  function Redraw (line 52) | func Redraw() {
  function DrawChan (line 61) | func DrawChan() chan bool {
  type screenCell (line 65) | type screenCell struct
  function ShowFakeCursor (line 80) | func ShowFakeCursor(x, y int) {
  function UseFake (line 91) | func UseFake() bool {
  function ShowFakeCursorMulti (line 98) | func ShowFakeCursorMulti(x, y int) {
  function ShowCursor (line 106) | func ShowCursor(x, y int) {
  function SetContent (line 116) | func SetContent(x, y int, mainc rune, combc []rune, style tcell.Style) {
  function RegisterRawSeq (line 130) | func RegisterRawSeq(r string) {
  function UnregisterRawSeq (line 144) | func UnregisterRawSeq(r string) {
  function TempFini (line 158) | func TempFini() bool {
  function TempStart (line 170) | func TempStart(screenWasNil bool) {
  function Init (line 182) | func Init() error {
  function InitSimScreen (line 242) | func InitSimScreen() (tcell.SimulationScreen, error) {

FILE: internal/shell/job.go
  function init (line 11) | func init() {
  type JobFunction (line 26) | type JobFunction struct
  type CallbackFile (line 33) | type CallbackFile struct
    method Write (line 46) | func (f *CallbackFile) Write(data []byte) (int, error) {
  type Job (line 41) | type Job struct
  function JobStart (line 56) | func JobStart(cmd string, onStdout, onStderr, onExit func(string, []any)...
  function JobSpawn (line 62) | func JobSpawn(cmdName string, cmdArgs []string, onStdout, onStderr, onEx...
  function JobStop (line 91) | func JobStop(j *Job) {
  function JobSend (line 96) | func JobSend(j *Job, data string) {

FILE: internal/shell/shell.go
  function ExecCommand (line 19) | func ExecCommand(name string, arg ...string) (string, error) {
  function RunCommand (line 35) | func RunCommand(input string) (string, error) {
  function RunBackgroundShell (line 51) | func RunBackgroundShell(input string) (func() string, error) {
  function RunInteractiveShell (line 72) | func RunInteractiveShell(input string, wait bool, getOutput bool) (strin...

FILE: internal/shell/terminal.go
  type TermType (line 13) | type TermType
  type CallbackFunc (line 14) | type CallbackFunc
  constant TTClose (line 17) | TTClose   = iota
  constant TTRunning (line 18) | TTRunning
  constant TTDone (line 19) | TTDone
  function init (line 24) | func init() {
  type Terminal (line 29) | type Terminal struct
    method HasSelection (line 42) | func (t *Terminal) HasSelection() bool {
    method Name (line 46) | func (t *Terminal) Name() string {
    method GetSelection (line 51) | func (t *Terminal) GetSelection(width int) string {
    method Start (line 72) | func (t *Terminal) Start(execCmd []string, getOutput bool, wait bool, ...
    method Stop (line 114) | func (t *Terminal) Stop() {
    method Close (line 127) | func (t *Terminal) Close() {
    method WriteString (line 144) | func (t *Terminal) WriteString(str string) {

FILE: internal/util/lua.go
  function LuaRuneAt (line 5) | func LuaRuneAt(str string, runeidx int) string {
  function LuaGetLeadingWhitespace (line 22) | func LuaGetLeadingWhitespace(s string) string {
  function LuaIsWordChar (line 38) | func LuaIsWordChar(s string) bool {

FILE: internal/util/profile.go
  function GetMemStats (line 13) | func GetMemStats() string {
  function Tic (line 19) | func Tic(s string) time.Time {
  function Toc (line 24) | func Toc(start time.Time) {

FILE: internal/util/unicode.go
  function isMark (line 21) | func isMark(r rune) bool {
  function DecodeCharacter (line 31) | func DecodeCharacter(b []byte) (rune, []rune, int) {
  function DecodeCharacterInString (line 50) | func DecodeCharacterInString(str string) (rune, []rune, int) {
  function CharacterCount (line 69) | func CharacterCount(b []byte) int {
  function CharacterCountInString (line 86) | func CharacterCountInString(str string) int {

FILE: internal/util/util.go
  constant FileMode (line 52) | FileMode os.FileMode = 0666
  constant BackupSuffix (line 54) | BackupSuffix = ".micro-backup"
  constant OverwriteFailMsg (line 56) | OverwriteFailMsg = `An error occurred while writing to the file:
  type OverwriteError (line 69) | type OverwriteError struct
    method Error (line 74) | func (e OverwriteError) Error() string {
    method Is (line 78) | func (e OverwriteError) Is(target error) bool {
    method Unwrap (line 82) | func (e OverwriteError) Unwrap() error {
  function init (line 86) | func init() {
  function SliceEnd (line 98) | func SliceEnd(slc []byte, index int) []byte {
  function SliceEndStr (line 116) | func SliceEndStr(str string, index int) string {
  function SliceStart (line 135) | func SliceStart(slc []byte, index int) []byte {
  function SliceStartStr (line 153) | func SliceStartStr(str string, index int) string {
  function SliceVisualEnd (line 174) | func SliceVisualEnd(b []byte, n, tabsize int) ([]byte, int, int) {
  function Abs (line 199) | func Abs(n int) int {
  function StringWidth (line 208) | func StringWidth(b []byte, n, tabsize int) int {
  function Min (line 236) | func Min(a, b int) int {
  function Max (line 244) | func Max(a, b int) int {
  function FSize (line 252) | func FSize(f *os.File) int64 {
  function IsWordChar (line 259) | func IsWordChar(r rune) bool {
  function IsNonWordChar (line 266) | func IsNonWordChar(r rune) bool {
  function IsSubwordDelimiter (line 273) | func IsSubwordDelimiter(r rune) bool {
  function IsAlphanumeric (line 279) | func IsAlphanumeric(r rune) bool {
  function IsUpperAlphanumeric (line 285) | func IsUpperAlphanumeric(r rune) bool {
  function IsLowerAlphanumeric (line 291) | func IsLowerAlphanumeric(r rune) bool {
  function IsUpperLetter (line 297) | func IsUpperLetter(r rune) bool {
  function IsLowerLetter (line 304) | func IsLowerLetter(r rune) bool {
  function Spaces (line 310) | func Spaces(n int) string {
  function IsSpaces (line 315) | func IsSpaces(str []byte) bool {
  function IsSpacesOrTabs (line 326) | func IsSpacesOrTabs(str []byte) bool {
  function IsWhitespace (line 337) | func IsWhitespace(c rune) bool {
  function IsBytesWhitespace (line 342) | func IsBytesWhitespace(b []byte) bool {
  function RunePos (line 353) | func RunePos(b []byte, i int) int {
  function IndexAnyUnquoted (line 360) | func IndexAnyUnquoted(s, chars string) int {
  function MakeRelative (line 380) | func MakeRelative(path, base string) (string, error) {
  function ReplaceHome (line 393) | func ReplaceHome(path string) (string, error) {
  function GetPathAndCursorPosition (line 422) | func GetPathAndCursorPosition(path string) (string, []string) {
  function GetModTime (line 437) | func GetModTime(path string) (time.Time, error) {
  function HashStringMd5 (line 445) | func HashStringMd5(str string) string {
  function EscapePathUrl (line 450) | func EscapePathUrl(path string) string {
  function EscapePathLegacy (line 455) | func EscapePathLegacy(path string) string {
  function DetermineEscapePath (line 473) | func DetermineEscapePath(dir string, path string) (string, string) {
  function GetLeadingWhitespace (line 493) | func GetLeadingWhitespace(b []byte) []byte {
  function GetTrailingWhitespace (line 509) | func GetTrailingWhitespace(b []byte) []byte {
  function HasTrailingWhitespace (line 525) | func HasTrailingWhitespace(b []byte) bool {
  function IntOpt (line 531) | func IntOpt(opt any) int {
  function GetCharPosInLine (line 538) | func GetCharPosInLine(b []byte, visualPos int, tabsize int) int {
  function ParseBool (line 569) | func ParseBool(str string) (bool, error) {
  function Clamp (line 580) | func Clamp(val, min, max int) int {
  function IsAutocomplete (line 590) | func IsAutocomplete(c rune) bool {
  function String (line 595) | func String(s []byte) string {
  function Unzip (line 600) | func Unzip(src, dest string) error {
  function HttpRequest (line 653) | func HttpRequest(method string, url string, headers []string) (resp *htt...
  function SafeWrite (line 687) | func SafeWrite(path string, bytes []byte, rename bool) error {

FILE: internal/util/util_test.go
  function TestStringWidth (line 9) | func TestStringWidth(t *testing.T) {
  function TestSliceVisualEnd (line 16) | func TestSliceVisualEnd(t *testing.T) {

FILE: internal/views/splits.go
  type SplitType (line 8) | type SplitType
  constant STVert (line 11) | STVert  = 0
  constant STHoriz (line 12) | STHoriz = 1
  constant STUndef (line 13) | STUndef = 2
  function NewID (line 19) | func NewID() uint64 {
  type View (line 25) | type View struct
  type Node (line 34) | type Node struct
    method IsLeaf (line 88) | func (n *Node) IsLeaf() bool {
    method ID (line 93) | func (n *Node) ID() uint64 {
    method CanResize (line 101) | func (n *Node) CanResize() bool {
    method PropScale (line 106) | func (n *Node) PropScale() bool {
    method SetResize (line 111) | func (n *Node) SetResize(b bool) {
    method SetPropScale (line 116) | func (n *Node) SetPropScale(b bool) {
    method Children (line 121) | func (n *Node) Children() []*Node {
    method GetNode (line 127) | func (n *Node) GetNode(id uint64) *Node {
    method vResizeSplit (line 143) | func (n *Node) vResizeSplit(i int, size int) bool {
    method hResizeSplit (line 164) | func (n *Node) hResizeSplit(i int, size int) bool {
    method ResizeSplit (line 187) | func (n *Node) ResizeSplit(size int) bool {
    method Resize (line 209) | func (n *Node) Resize(w, h int) {
    method alignSizes (line 236) | func (n *Node) alignSizes(totw, toth int) {
    method markSizes (line 249) | func (n *Node) markSizes() {
    method markResize (line 257) | func (n *Node) markResize() {
    method vVSplit (line 263) | func (n *Node) vVSplit(right bool) uint64 {
    method hHSplit (line 274) | func (n *Node) hHSplit(bottom bool) uint64 {
    method getResizeInfo (line 286) | func (n *Node) getResizeInfo(h bool) (int, int) {
    method applyNewSize (line 311) | func (n *Node) applyNewSize(size int, h bool) {
    method vHSplit (line 339) | func (n *Node) vHSplit(i int, right bool) uint64 {
    method hVSplit (line 375) | func (n *Node) hVSplit(i int, right bool) uint64 {
    method HSplit (line 412) | func (n *Node) HSplit(bottom bool) uint64 {
    method VSplit (line 428) | func (n *Node) VSplit(right bool) uint64 {
    method unsplit (line 442) | func (n *Node) unsplit(i int) {
    method Unsplit (line 464) | func (n *Node) Unsplit() bool {
    method flatten (line 485) | func (n *Node) flatten() {
    method String (line 544) | func (n *Node) String() string {
  function NewNode (line 59) | func NewNode(Kind SplitType, x, y, w, h int, parent *Node, id uint64) *N...
  function NewRoot (line 81) | func NewRoot(x, y, w, h int) *Node {

FILE: internal/views/splits_test.go
  function TestHSplit (line 8) | func TestHSplit(t *testing.T) {

FILE: pkg/highlight/highlighter.go
  function sliceStart (line 8) | func sliceStart(slc []byte, index int) []byte {
  function sliceEnd (line 25) | func sliceEnd(slc []byte, index int) []byte {
  function runePos (line 44) | func runePos(p int, str []byte) int {
  type State (line 55) | type State
  type LineStates (line 58) | type LineStates interface
  type Highlighter (line 69) | type Highlighter struct
    method highlightRegion (line 113) | func (h *Highlighter) highlightRegion(highlights LineMatch, start int,...
    method highlightEmptyRegion (line 207) | func (h *Highlighter) highlightEmptyRegion(highlights LineMatch, start...
    method HighlightString (line 272) | func (h *Highlighter) HighlightString(input string) []LineMatch {
    method HighlightStates (line 291) | func (h *Highlighter) HighlightStates(input LineStates) {
    method HighlightMatches (line 318) | func (h *Highlighter) HighlightMatches(input LineStates, startline, en...
    method ReHighlightStates (line 344) | func (h *Highlighter) ReHighlightStates(input LineStates, startline in...
    method ReHighlightLine (line 386) | func (h *Highlighter) ReHighlightLine(input LineStates, lineN int) {
  function NewHighlighter (line 75) | func NewHighlighter(def *Def) *Highlighter {
  type LineMatch (line 83) | type LineMatch
  function findIndex (line 85) | func findIndex(regex *regexp.Regexp, skip *regexp.Regexp, str []byte) []...
  function findAllIndex (line 104) | func findAllIndex(regex *regexp.Regexp, str []byte) [][]int {

FILE: pkg/highlight/parser.go
  type Group (line 13) | type Group
    method String (line 21) | func (g Group) String() string {
  type Def (line 34) | type Def struct
  type Header (line 39) | type Header struct
    method MatchFileName (line 158) | func (header *Header) MatchFileName(filename string) bool {
    method MatchFileHeader (line 166) | func (header *Header) MatchFileHeader(firstLine []byte) bool {
    method HasFileSignature (line 175) | func (header *Header) HasFileSignature() bool {
    method MatchFileSignature (line 180) | func (header *Header) MatchFileSignature(line []byte) bool {
  type HeaderYaml (line 46) | type HeaderYaml struct
  type File (line 55) | type File struct
  type pattern (line 63) | type pattern struct
  type rules (line 70) | type rules struct
  type region (line 81) | type region struct
  function init (line 91) | func init() {
  function MakeHeader (line 99) | func MakeHeader(data []byte) (*Header, error) {
  function MakeHeaderYaml (line 130) | func MakeHeaderYaml(data []byte) (*Header, error) {
  function ParseFile (line 188) | func ParseFile(input []byte) (f *File, err error) {
  function ParseDef (line 229) | func ParseDef(f *File, header *Header) (s *Def, err error) {
  function HasIncludes (line 268) | func HasIncludes(d *Def) bool {
  function hasIncludesInRegion (line 276) | func hasIncludesInRegion(region *region) bool {
  function GetIncludes (line 285) | func GetIncludes(d *Def) []string {
  function getIncludesInRegion (line 293) | func getIncludesInRegion(region *region) []string {
  function ResolveIncludes (line 303) | func ResolveIncludes(def *Def, files []*File) {
  function resolveIncludesInDef (line 307) | func resolveIncludesInDef(files []*File, d *Def) {
  function resolveIncludesInRegion (line 323) | func resolveIncludesInRegion(files []*File, region *region) {
  function parseRules (line 339) | func parseRules(input []any, curRegion *region) (ru *rules, err error) {
  function parseRegion (line 395) | func parseRegion(group string, regionInfo map[any]any, prevRegion *regio...

FILE: pkg/highlight/unicode.go
  function isMark (line 10) | func isMark(r rune) bool {
  function DecodeCharacter (line 20) | func DecodeCharacter(b []byte) (rune, []rune, int) {
  function DecodeCharacterInString (line 39) | func DecodeCharacterInString(str string) (rune, []rune, int) {
  function CharacterCount (line 58) | func CharacterCount(b []byte) int {
  function CharacterCountInString (line 75) | func CharacterCountInString(str string) int {

FILE: runtime/runtime.go
  function fixPath (line 14) | func fixPath(name string) string {
  function AssetDir (line 19) | func AssetDir(name string) ([]string, error) {
  function Asset (line 33) | func Asset(name string) ([]byte, error) {

FILE: runtime/runtime_test.go
  function TestAssetDir (line 9) | func TestAssetDir(t *testing.T) {

FILE: runtime/syntax/make_headers.go
  type HeaderYaml (line 16) | type HeaderYaml struct
  type Header (line 25) | type Header struct
  function main (line 32) | func main() {
  function convert (line 45) | func convert(name string) {
  function encode (line 59) | func encode(name string, c HeaderYaml) {
  function decode (line 68) | func decode(name string) Header {

FILE: runtime/syntax/syntax_converter.go
  type SingleRule (line 12) | type SingleRule struct
  type MultiRule (line 17) | type MultiRule struct
  function JoinRule (line 25) | func JoinRule(rule string) string {
  function parseFile (line 31) | func parseFile(text, filename string) (filetype, syntax, header string, ...
  function generateFile (line 132) | func generateFile(filetype, syntax, header string, rules []any) string {
  function main (line 157) | func main() {

FILE: tools/build-date.go
  function main (line 12) | func main() {

FILE: tools/build-version.go
  function getTag (line 14) | func getTag(match ...string) (string, *semver.PRVersion) {
  function main (line 40) | func main() {

FILE: tools/info-plist.go
  function main (line 11) | func main() {

FILE: tools/remove-nightly-assets.go
  function main (line 15) | func main() {

FILE: tools/testgen.go
  type walker (line 16) | type walker struct
    method Enter (line 20) | func (w *walker) Enter(node ast.Node) ast.Visitor {
    method Exit (line 25) | func (w *walker) Exit(node ast.Node) {
  function getAllNodes (line 28) | func getAllNodes(node ast.Node) []ast.Node {
  function getCalls (line 34) | func getCalls(node ast.Node, name string) []*ast.CallExpression {
  function getPropertyValue (line 55) | func getPropertyValue(node ast.Node, key string) ast.Expression {
  type operation (line 64) | type operation struct
  type check (line 72) | type check struct
  type test (line 78) | type test struct
  function stringSliceToGoSource (line 83) | func stringSliceToGoSource(slice []string) string {
  function testToGoTest (line 93) | func testToGoTest(test test, name string) string {
  function nodeToStringSlice (line 122) | func nodeToStringSlice(node ast.Node) []string {
  function nodeToStringSlice2 (line 130) | func nodeToStringSlice2(node ast.Node) []string {
  function nodeToInt (line 138) | func nodeToInt(node ast.Node) int {
  function getChecks (line 142) | func getChecks(node ast.Node) []check {
  function getTests (line 195) | func getTests(node ast.Node) []test {
  function main (line 208) | func main() {
Condensed preview — 328 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,356K chars).
[
  {
    "path": ".editorconfig",
    "chars": 152,
    "preview": "# See https://editorconfig.org\n\n# In Go files we indent with tabs but still \n# set indent_size to control the GitHub web"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/01-bug.yml",
    "chars": 567,
    "preview": "name: Bug Report\ndescription: File a bug report.\ntitle: \"<title>\"\nlabels: [\"bug\", \"triage\"]\nbody:\n- type: textarea\n  att"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/02-feature.yml",
    "chars": 235,
    "preview": "name: Feature Request\ndescription: File a feature request.\ntitle: \"<title>\"\nlabels: [\"feature\"]\nbody:\n- type: textarea\n "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 28,
    "preview": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/workflows/nightly.yaml",
    "chars": 955,
    "preview": "name: Nightly builds\non:\n  workflow_dispatch: # Allows manual trigger\n  schedule:\n    - cron: '0 0 * * *'\njobs:\n  nightl"
  },
  {
    "path": ".github/workflows/release.yaml",
    "chars": 748,
    "preview": "name: Release builds\non:\n  workflow_dispatch: # Allows manual trigger\n  # push:\n  #   tags:\n  #     - 'v*.*.*' # automat"
  },
  {
    "path": ".github/workflows/test.yaml",
    "chars": 527,
    "preview": "on: [push, pull_request]\nname: Build and Test\njobs:\n  test:\n    strategy:\n      matrix:\n        go-version: [1.19.x, 1.2"
  },
  {
    "path": ".gitignore",
    "chars": 209,
    "preview": ".DS_Store\n\nmicro\nmicro.exe\n!cmd/micro\nbinaries/\ntmp.sh\ntest/\n.idea/\npackages/\ntodo.txt\ntest.txt\nlog.txt\n*.old\nbenchmark_"
  },
  {
    "path": "LICENSE",
    "chars": 1086,
    "preview": "MIT License\n\nCopyright (c) 2016-2020: Zachary Yedidia, et al.\n\nPermission is hereby granted, free of charge, to any pers"
  },
  {
    "path": "LICENSE-THIRD-PARTY",
    "chars": 64173,
    "preview": "Third party libraries directly used by micro and their licenses\n================\n\ngithub.com/golang/go/LICENSE\n========="
  },
  {
    "path": "Makefile",
    "chars": 2652,
    "preview": ".PHONY: runtime build generate build-quick\n\nVERSION = $(shell GOOS=$(shell go env GOHOSTOS) GOARCH=$(shell go env GOHOST"
  },
  {
    "path": "README.md",
    "chars": 13684,
    "preview": "<img alt=\"micro logo\" src=\"./assets/micro-logo-drop.svg\" width=\"500px\"/>\n\n![Test Workflow](https://github.com/micro-edit"
  },
  {
    "path": "assets/packaging/deb/micro.postinst",
    "chars": 249,
    "preview": "#!/bin/sh\n\nset -e\n\nif [ \"$1\" = \"configure\" ] || [ \"$1\" = \"abort-upgrade\" ]; then\n    update-alternatives --install /usr/"
  },
  {
    "path": "assets/packaging/deb/micro.prerm",
    "chars": 108,
    "preview": "#!/bin/sh\n\nset -e\n\nif [ \"$1\" != \"upgrade\" ]; then\n    update-alternatives --remove editor /usr/bin/micro\nfi\n"
  },
  {
    "path": "assets/packaging/micro.1",
    "chars": 3763,
    "preview": ".TH micro 1 \"2025-09-03\"\n.SH NAME\nmicro \\- A modern and intuitive terminal-based text editor\n.SH SYNOPSIS\n.B micro\n.RI ["
  },
  {
    "path": "assets/packaging/micro.desktop",
    "chars": 537,
    "preview": "[Desktop Entry]\n\nName=Micro\nGenericName=Text Editor\nComment=Edit text files in a terminal\n\nIcon=micro\nType=Application\nC"
  },
  {
    "path": "cmd/micro/clean.go",
    "chars": 3892,
    "preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com"
  },
  {
    "path": "cmd/micro/debug.go",
    "chars": 646,
    "preview": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/micro-editor/micro/v2/internal/util\"\n)\n\n// NullWriter simply sends wri"
  },
  {
    "path": "cmd/micro/initlua.go",
    "chars": 7323,
    "preview": "package main\n\nimport (\n\t\"log\"\n\t\"time\"\n\n\tlua \"github.com/yuin/gopher-lua\"\n\tluar \"layeh.com/gopher-luar\"\n\n\t\"github.com/mic"
  },
  {
    "path": "cmd/micro/micro.go",
    "chars": 14010,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"runtime/pp"
  },
  {
    "path": "cmd/micro/micro_test.go",
    "chars": 7007,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/go-errors/errors\"\n\t\"github.com/micro-editor/micro/v2"
  },
  {
    "path": "data/io.github.zyedidia.micro.metainfo.xml",
    "chars": 2242,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<component type=\"desktop-application\">\n\t<id>io.github.zyedidia.micro</id>\n\t<launc"
  },
  {
    "path": "data/micro.json",
    "chars": 17374,
    "preview": "{\n    \"$comment\": \"https://github.com/micro-editor/micro\",\n    \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n   "
  },
  {
    "path": "go.mod",
    "chars": 1425,
    "preview": "module github.com/micro-editor/micro/v2\n\nrequire (\n\tgithub.com/blang/semver v3.5.1+incompatible\n\tgithub.com/dustin/go-hu"
  },
  {
    "path": "go.sum",
    "chars": 6828,
    "preview": "github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=\ngithub.com/blang/semver v3.5"
  },
  {
    "path": "internal/action/actions.go",
    "chars": 59363,
    "preview": "package action\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"regexp\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\tshellquote \"github.co"
  },
  {
    "path": "internal/action/actions_other.go",
    "chars": 159,
    "preview": "//go:build plan9 || nacl || windows\n\npackage action\n\nfunc (*BufPane) Suspend() bool {\n\tInfoBar.Error(\"Suspend is only su"
  },
  {
    "path": "internal/action/actions_posix.go",
    "chars": 639,
    "preview": "//go:build linux || darwin || dragonfly || solaris || openbsd || netbsd || freebsd\n\npackage action\n\nimport (\n\t\"syscall\"\n"
  },
  {
    "path": "internal/action/bindings.go",
    "chars": 13374,
    "preview": "package action\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\t\"unicod"
  },
  {
    "path": "internal/action/bufpane.go",
    "chars": 28585,
    "preview": "package action\n\nimport (\n\t\"strings\"\n\t\"time\"\n\n\tluar \"layeh.com/gopher-luar\"\n\n\t\"github.com/micro-editor/micro/v2/internal/"
  },
  {
    "path": "internal/action/command.go",
    "chars": 29626,
    "preview": "package action\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"s"
  },
  {
    "path": "internal/action/defaults.go",
    "chars": 468,
    "preview": "package action\n\nvar termdefaults = map[string]string{\n\t\"<Ctrl-q><Ctrl-q>\": \"Exit\",\n\t\"<Ctrl-e><Ctrl-e>\": \"CommandMode\",\n\t"
  },
  {
    "path": "internal/action/defaults_darwin.go",
    "chars": 6036,
    "preview": "package action\n\nvar bufdefaults = map[string]string{\n\t\"Up\":             \"CursorUp\",\n\t\"Down\":           \"CursorDown\",\n\t\"R"
  },
  {
    "path": "internal/action/defaults_other.go",
    "chars": 6074,
    "preview": "//go:build !darwin\n// +build !darwin\n\npackage action\n\nvar bufdefaults = map[string]string{\n\t\"Up\":             \"CursorUp\""
  },
  {
    "path": "internal/action/events.go",
    "chars": 3586,
    "preview": "package action\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/micro-editor/tcell/v2\"\n)\n\ntype Event interfa"
  },
  {
    "path": "internal/action/globals.go",
    "chars": 913,
    "preview": "package action\n\nimport \"github.com/micro-editor/micro/v2/internal/buffer\"\n\n// InfoBar is the global info bar.\nvar InfoBa"
  },
  {
    "path": "internal/action/infocomplete.go",
    "chars": 8745,
    "preview": "package action\n\nimport (\n\t\"bytes\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n\t\"github.com/m"
  },
  {
    "path": "internal/action/infopane.go",
    "chars": 6013,
    "preview": "package action\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n\t\"github.com/micro-editor/micro/v"
  },
  {
    "path": "internal/action/keytree.go",
    "chars": 6793,
    "preview": "package action\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/micro-editor/tcell/v2\"\n)\n\ntype PaneKeyAction func(Pane) bool\ntype PaneMo"
  },
  {
    "path": "internal/action/pane.go",
    "chars": 273,
    "preview": "package action\n\nimport (\n\t\"github.com/micro-editor/micro/v2/internal/display\"\n)\n\n// A Pane is a general interface for a "
  },
  {
    "path": "internal/action/rawpane.go",
    "chars": 1004,
    "preview": "package action\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n\t\"github.com/micro-edito"
  },
  {
    "path": "internal/action/tab.go",
    "chars": 9205,
    "preview": "package action\n\nimport (\n\tluar \"layeh.com/gopher-luar\"\n\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n\t\"github.com"
  },
  {
    "path": "internal/action/terminal_supported.go",
    "chars": 1317,
    "preview": "//go:build linux || darwin || dragonfly || solaris || openbsd || netbsd || freebsd\n\npackage action\n\nimport (\n\tshellquote"
  },
  {
    "path": "internal/action/terminal_unsupported.go",
    "chars": 445,
    "preview": "//go:build plan9 || nacl || windows\n\npackage action\n\nimport \"errors\"\n\n// TermEmuSupported is a constant that marks if th"
  },
  {
    "path": "internal/action/termpane.go",
    "chars": 5269,
    "preview": "package action\n\nimport (\n\t\"errors\"\n\t\"runtime\"\n\n\t\"github.com/micro-editor/micro/v2/internal/clipboard\"\n\t\"github.com/micro"
  },
  {
    "path": "internal/buffer/autocomplete.go",
    "chars": 4967,
    "preview": "package buffer\n\nimport (\n\t\"bytes\"\n\t\"io/fs\"\n\t\"os\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/micro-editor/micro/v2/internal/util\"\n)"
  },
  {
    "path": "internal/buffer/backup.go",
    "chars": 4598,
    "preview": "package buffer\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/micro-editor/micro/v2/internal/c"
  },
  {
    "path": "internal/buffer/buffer.go",
    "chars": 37255,
    "preview": "package buffer\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/md5\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strcon"
  },
  {
    "path": "internal/buffer/buffer_generated_test.go",
    "chars": 22783,
    "preview": "// This file is generated from VSCode model tests by the testgen tool.\n// DO NOT EDIT THIS FILE BY HAND; your changes wi"
  },
  {
    "path": "internal/buffer/buffer_test.go",
    "chars": 6753,
    "preview": "package buffer\n\nimport (\n\t\"math/rand\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/micro-editor/micro/v2/internal/config\"\n\tulua \""
  },
  {
    "path": "internal/buffer/cursor.go",
    "chars": 14588,
    "preview": "package buffer\n\nimport (\n\t\"github.com/micro-editor/micro/v2/internal/clipboard\"\n\t\"github.com/micro-editor/micro/v2/inter"
  },
  {
    "path": "internal/buffer/eventhandler.go",
    "chars": 10183,
    "preview": "package buffer\n\nimport (\n\t\"bytes\"\n\t\"time\"\n\n\t\"github.com/micro-editor/micro/v2/internal/config\"\n\tulua \"github.com/micro-e"
  },
  {
    "path": "internal/buffer/line_array.go",
    "chars": 11764,
    "preview": "package buffer\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"io\"\n\t\"sync\"\n\n\t\"github.com/micro-editor/micro/v2/internal/util\"\n\t\"github.com"
  },
  {
    "path": "internal/buffer/line_array_test.go",
    "chars": 1727,
    "preview": "package buffer\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nvar unicode_txt = `An preost we"
  },
  {
    "path": "internal/buffer/loc.go",
    "chars": 3078,
    "preview": "package buffer\n\nimport (\n\t\"github.com/micro-editor/micro/v2/internal/util\"\n)\n\n// Loc stores a location\ntype Loc struct {"
  },
  {
    "path": "internal/buffer/message.go",
    "chars": 1876,
    "preview": "package buffer\n\nimport (\n\t\"github.com/micro-editor/micro/v2/internal/config\"\n\t\"github.com/micro-editor/tcell/v2\"\n)\n\ntype"
  },
  {
    "path": "internal/buffer/save.go",
    "chars": 9385,
    "preview": "package buffer\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"errors\"\n\t\"io\"\n\t\"io/fs\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\t\"run"
  },
  {
    "path": "internal/buffer/search.go",
    "chars": 6281,
    "preview": "package buffer\n\nimport (\n\t\"regexp\"\n\t\"unicode/utf8\"\n\n\t\"github.com/micro-editor/micro/v2/internal/util\"\n)\n\n// We want \"^\" "
  },
  {
    "path": "internal/buffer/serialize.go",
    "chars": 2596,
    "preview": "package buffer\n\nimport (\n\t\"bytes\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/micro-editor/mi"
  },
  {
    "path": "internal/buffer/settings.go",
    "chars": 4407,
    "preview": "package buffer\n\nimport (\n\t\"crypto/md5\"\n\t\"reflect\"\n\n\t\"github.com/micro-editor/micro/v2/internal/config\"\n\tulua \"github.com"
  },
  {
    "path": "internal/buffer/stack.go",
    "chars": 849,
    "preview": "package buffer\n\n// TEStack is a simple implementation of a LIFO stack for text events\ntype TEStack struct {\n\tTop  *Eleme"
  },
  {
    "path": "internal/buffer/stack_test.go",
    "chars": 626,
    "preview": "package buffer\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStack(t *testing.T) {\n\ts "
  },
  {
    "path": "internal/clipboard/clipboard.go",
    "chars": 4189,
    "preview": "package clipboard\n\nimport (\n\t\"errors\"\n\n\t\"github.com/zyedidia/clipper\"\n)\n\ntype Method int\n\nconst (\n\t// External relies on"
  },
  {
    "path": "internal/clipboard/internal.go",
    "chars": 292,
    "preview": "package clipboard\n\ntype internalClipboard map[Register]string\n\nvar internal internalClipboard\n\nfunc init() {\n\tinternal ="
  },
  {
    "path": "internal/clipboard/multi.go",
    "chars": 1313,
    "preview": "package clipboard\n\nimport (\n\t\"bytes\"\n)\n\n// For storing multi cursor clipboard contents\ntype multiClipboard map[Register]"
  },
  {
    "path": "internal/clipboard/terminal.go",
    "chars": 690,
    "preview": "package clipboard\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/micro-editor/micro/v2/internal/screen\"\n\t\"github.com/micro-ed"
  },
  {
    "path": "internal/config/autosave.go",
    "chars": 779,
    "preview": "package config\n\nimport (\n\t\"time\"\n)\n\nvar Autosave chan bool\nvar autotime chan float64\n\nfunc init() {\n\tAutosave = make(cha"
  },
  {
    "path": "internal/config/colorscheme.go",
    "chars": 7234,
    "preview": "package config\n\nimport (\n\t\"errors\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/micro-editor/tcell/v2\"\n)\n\n// DefStyle i"
  },
  {
    "path": "internal/config/colorscheme_test.go",
    "chars": 1904,
    "preview": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/micro-editor/tcell/v2\"\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc T"
  },
  {
    "path": "internal/config/config.go",
    "chars": 1433,
    "preview": "package config\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\n\thomedir \"github.com/mitchellh/go-homedir\"\n)\n\nvar ConfigDir s"
  },
  {
    "path": "internal/config/globals.go",
    "chars": 353,
    "preview": "package config\n\nconst (\n\tDoubleClickThreshold = 400 // How many milliseconds to wait before a second click is not a doub"
  },
  {
    "path": "internal/config/plugin.go",
    "chars": 3394,
    "preview": "package config\n\nimport (\n\t\"errors\"\n\t\"log\"\n\n\tulua \"github.com/micro-editor/micro/v2/internal/lua\"\n\tlua \"github.com/yuin/g"
  },
  {
    "path": "internal/config/plugin_installer.go",
    "chars": 18490,
    "preview": "package config\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\t\"sy"
  },
  {
    "path": "internal/config/plugin_installer_test.go",
    "chars": 1295,
    "preview": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/blang/semver\"\n\n\t\"github.com/micro-editor/json5\"\n)\n\nfunc TestDependency"
  },
  {
    "path": "internal/config/plugin_manager.go",
    "chars": 1391,
    "preview": "package config\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n)\n\nvar (\n\tErrMissingName = errors.New(\"Missing or empty nam"
  },
  {
    "path": "internal/config/rtfiles.go",
    "chars": 8998,
    "preview": "package config\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\trt \"github.com/micro-editor/micr"
  },
  {
    "path": "internal/config/rtfiles_test.go",
    "chars": 981,
    "preview": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc init() {\n\tInitRuntimeFiles(false)\n}\n\n"
  },
  {
    "path": "internal/config/settings.go",
    "chars": 15770,
    "preview": "package config\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"str"
  },
  {
    "path": "internal/display/bufwindow.go",
    "chars": 22755,
    "preview": "package display\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n\n\trunewidth \"github.com/mattn/go-runewidth\"\n\t\"github.com/micro-editor/mi"
  },
  {
    "path": "internal/display/infowindow.go",
    "chars": 6765,
    "preview": "package display\n\nimport (\n\trunewidth \"github.com/mattn/go-runewidth\"\n\t\"github.com/micro-editor/micro/v2/internal/buffer\""
  },
  {
    "path": "internal/display/softwrap.go",
    "chars": 7512,
    "preview": "package display\n\nimport (\n\trunewidth \"github.com/mattn/go-runewidth\"\n\t\"github.com/micro-editor/micro/v2/internal/buffer\""
  },
  {
    "path": "internal/display/statusline.go",
    "chars": 5582,
    "preview": "package display\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\n\tluar \"layeh.com/gopher-luar\"\n\n\trunewidth \"gi"
  },
  {
    "path": "internal/display/tabwindow.go",
    "chars": 3631,
    "preview": "package display\n\nimport (\n\trunewidth \"github.com/mattn/go-runewidth\"\n\t\"github.com/micro-editor/micro/v2/internal/buffer\""
  },
  {
    "path": "internal/display/termwindow.go",
    "chars": 2822,
    "preview": "package display\n\nimport (\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n\t\"github.com/micro-editor/micro/v2/interna"
  },
  {
    "path": "internal/display/uiwindow.go",
    "chars": 1924,
    "preview": "package display\n\nimport (\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n\t\"github.com/micro-editor/micro/v2/interna"
  },
  {
    "path": "internal/display/window.go",
    "chars": 778,
    "preview": "package display\n\nimport (\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n)\n\ntype View struct {\n\tX, Y          int /"
  },
  {
    "path": "internal/info/gutter.go",
    "chars": 397,
    "preview": "package info\n\n// A GutterMessage is a message displayed on the side of the editor\ntype GutterMessage struct {\n\tlineNum i"
  },
  {
    "path": "internal/info/history.go",
    "chars": 4131,
    "preview": "package info\n\nimport (\n\t\"bytes\"\n\t\"encoding/gob\"\n\t\"errors\"\n\t\"io/fs\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/micro"
  },
  {
    "path": "internal/info/infobuffer.go",
    "chars": 4830,
    "preview": "package info\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n)\n\n// The InfoBuf displays messages a"
  },
  {
    "path": "internal/lua/lua.go",
    "chars": 25107,
    "preview": "package lua\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"math\"\n\t\"math/rand\"\n\t\"net\"\n\t\"net/http"
  },
  {
    "path": "internal/screen/message.go",
    "chars": 1667,
    "preview": "package screen\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// TermMessage sends a message to the user in th"
  },
  {
    "path": "internal/screen/screen.go",
    "chars": 6362,
    "preview": "package screen\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"os\"\n\t\"sync\"\n\n\t\"github.com/micro-editor/micro/v2/internal/config\"\n\t\"github.co"
  },
  {
    "path": "internal/shell/job.go",
    "chars": 2765,
    "preview": "package shell\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"os/exec\"\n)\n\nvar Jobs chan JobFunction\n\nfunc init() {\n\tJobs = make(chan JobFunct"
  },
  {
    "path": "internal/shell/shell.go",
    "chars": 3313,
    "preview": "package shell\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/signal\"\n\n\tshellquote \"github.com/kballard/"
  },
  {
    "path": "internal/shell/terminal.go",
    "chars": 3049,
    "preview": "package shell\n\nimport (\n\t\"bytes\"\n\t\"os/exec\"\n\t\"strconv\"\n\n\t\"github.com/micro-editor/micro/v2/internal/buffer\"\n\t\"github.com"
  },
  {
    "path": "internal/util/lua.go",
    "chars": 843,
    "preview": "package util\n\n// LuaRuneAt is a helper function for lua plugins to return the rune\n// at an index within a string\nfunc L"
  },
  {
    "path": "internal/util/profile.go",
    "chars": 641,
    "preview": "package util\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"runtime\"\n\t\"time\"\n\n\thumanize \"github.com/dustin/go-humanize\"\n)\n\n// GetMemStats ret"
  },
  {
    "path": "internal/util/unicode.go",
    "chars": 2324,
    "preview": "package util\n\nimport (\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\n// Unicode is annoying. A \"code point\" (rune in Go-speak) may need "
  },
  {
    "path": "internal/util/util.go",
    "chars": 18245,
    "preview": "package util\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"crypto/md5\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os"
  },
  {
    "path": "internal/util/util_test.go",
    "chars": 708,
    "preview": "package util\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestStringWidth(t *testing.T) {\n\tbytes "
  },
  {
    "path": "internal/views/splits.go",
    "chars": 12504,
    "preview": "package views\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype SplitType uint8\n\nconst (\n\tSTVert  = 0\n\tSTHoriz = 1\n\tSTUndef = 2\n)\n\nvar"
  },
  {
    "path": "internal/views/splits_test.go",
    "chars": 256,
    "preview": "package views\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestHSplit(t *testing.T) {\n\troot := NewRoot(0, 0, 80, 80)\n\tn1 := root."
  },
  {
    "path": "pkg/highlight/highlighter.go",
    "chars": 10090,
    "preview": "package highlight\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n)\n\nfunc sliceStart(slc []byte, index int) []byte {\n\tlen := len(slc)\n\ti "
  },
  {
    "path": "pkg/highlight/parser.go",
    "chars": 11337,
    "preview": "package highlight\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"regexp\"\n\n\t\"gopkg.in/yaml.v2\"\n)\n\n// A Group represents a syntax g"
  },
  {
    "path": "pkg/highlight/unicode.go",
    "chars": 1617,
    "preview": "package highlight\n\nimport (\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\nvar minMark = rune(unicode.Mark.R16[0].Lo)\n\nfunc isMark(r rune"
  },
  {
    "path": "runtime/README.md",
    "chars": 307,
    "preview": "# Runtime files for Micro\n\nThis directory will be embedded in the Go binary for portability, but it may just as well be "
  },
  {
    "path": "runtime/colorschemes/atom-dark.micro",
    "chars": 1237,
    "preview": "color-link default \"#C5C8C6,#1D1F21\"\ncolor-link comment \"#7C7C7C,#1D1F21\"\ncolor-link identifier \"#F9EE98,#1D1F21\"\ncolor-"
  },
  {
    "path": "runtime/colorschemes/bubblegum.micro",
    "chars": 983,
    "preview": "color-link default \"241,231\"\ncolor-link comment \"246,231\"\ncolor-link constant \"130,231\"\ncolor-link constant.string \"136,"
  },
  {
    "path": "runtime/colorschemes/cmc-16.micro",
    "chars": 1680,
    "preview": "#CaptainMcClellan's personal color scheme.\n#16 colour version.\ncolor-link comment \"bold black\"\ncolor-link constant \"cyan"
  },
  {
    "path": "runtime/colorschemes/cmc-tc.micro",
    "chars": 1597,
    "preview": "#CaptainMcClellan's personal colour scheme.\n#Full colour edition.\ncolor-link default \"#aaaaaa,#1e2124\"\ncolor-link commen"
  },
  {
    "path": "runtime/colorschemes/darcula.micro",
    "chars": 1301,
    "preview": "color-link default \"#CCCCCC,#242424\"\ncolor-link comment \"#707070,#242424\"\ncolor-link identifier \"#FFC66D,#242424\"\ncolor-"
  },
  {
    "path": "runtime/colorschemes/default.micro",
    "chars": 18,
    "preview": "include \"monokai\"\n"
  },
  {
    "path": "runtime/colorschemes/dracula-tc.micro",
    "chars": 1243,
    "preview": "color-link default \"#F8F8F2,#282A36\"\ncolor-link comment \"#6272A4\"\n\ncolor-link identifier \"#50FA7B\"\ncolor-link identifier"
  },
  {
    "path": "runtime/colorschemes/dukedark-tc.micro",
    "chars": 1541,
    "preview": "color-link color-column \"#001e28\"\ncolor-link comment \"#608b4e,#001e28\"\ncolor-link constant.bool \"#fd971f,#001e28\"\ncolor-"
  },
  {
    "path": "runtime/colorschemes/dukelight-tc.micro",
    "chars": 1561,
    "preview": "color-link color-column \"#f0f0f0\"\ncolor-link comment \"#3f7f5f,#f0f0f0\"\ncolor-link constant.bool \"#641e00,#f0f0f0\"\ncolor-"
  },
  {
    "path": "runtime/colorschemes/dukeubuntu-tc.micro",
    "chars": 1541,
    "preview": "color-link color-column \"#2d0023\"\ncolor-link comment \"#886484,#2d0023\"\ncolor-link constant.bool \"#fd971f,#2d0023\"\ncolor-"
  },
  {
    "path": "runtime/colorschemes/geany.micro",
    "chars": 886,
    "preview": "#Geany\ncolor-link comment \"red\"\ncolor-link constant \"default\"\ncolor-link constant.string \"bold yellow\"\ncolor-link identi"
  },
  {
    "path": "runtime/colorschemes/gotham.micro",
    "chars": 1116,
    "preview": "color-link default \"#99D1CE,#0C1014\"\ncolor-link comment \"#245361,#0C1014\"\ncolor-link identifier \"#599CAB,#0C1014\"\ncolor-"
  },
  {
    "path": "runtime/colorschemes/gruvbox-tc.micro",
    "chars": 1112,
    "preview": "color-link default \"#ebdbb2,#282828\"\ncolor-link comment \"#928374,#282828\"\ncolor-link symbol \"#d79921,#282828\"\ncolor-link"
  },
  {
    "path": "runtime/colorschemes/gruvbox.micro",
    "chars": 797,
    "preview": "color-link default \"223,235\"\ncolor-link comment \"243,235\"\ncolor-link constant \"175,235\"\ncolor-link constant.string \"142,"
  },
  {
    "path": "runtime/colorschemes/material-tc.micro",
    "chars": 1419,
    "preview": "color-link color-column \"#263238\"\ncolor-link comment \"#4F6875,#263238\"\ncolor-link constant \"#F07178,#263238\"\ncolor-link "
  },
  {
    "path": "runtime/colorschemes/monokai-dark.micro",
    "chars": 968,
    "preview": "color-link default \"#D5D8D6,#1D0000\"\ncolor-link comment \"#75715E\"\ncolor-link identifier \"#66D9EF\"\ncolor-link constant \"#"
  },
  {
    "path": "runtime/colorschemes/monokai.micro",
    "chars": 1310,
    "preview": "color-link default \"#F8F8F2,#282828\"\ncolor-link comment \"#75715E,#282828\"\ncolor-link identifier \"#66D9EF,#282828\"\ncolor-"
  },
  {
    "path": "runtime/colorschemes/one-dark.micro",
    "chars": 1336,
    "preview": "color-link default \"#ABB2BF,#21252C\"\ncolor-link color-column \"#282C34\"\ncolor-link comment \"#5C6370\"\ncolor-link constant "
  },
  {
    "path": "runtime/colorschemes/railscast.micro",
    "chars": 1416,
    "preview": "color-link default \"#e6e1dc,#2b2b2b\"\ncolor-link comment \"#bc9458,#2b2b2b\"\ncolor-link statement \"#cc7833,#2b2b2b\"\ncolor-l"
  },
  {
    "path": "runtime/colorschemes/simple.micro",
    "chars": 1068,
    "preview": "color-link comment \"blue\"\ncolor-link constant \"red\"\ncolor-link identifier \"cyan\"\ncolor-link statement \"yellow\"\ncolor-lin"
  },
  {
    "path": "runtime/colorschemes/solarized-tc.micro",
    "chars": 1195,
    "preview": "color-link default \"#839496,#002833\"\ncolor-link comment \"#586E75,#002833\"\ncolor-link identifier \"#268BD2,#002833\"\ncolor-"
  },
  {
    "path": "runtime/colorschemes/solarized.micro",
    "chars": 1031,
    "preview": "color-link comment \"bold brightgreen\"\ncolor-link constant \"cyan\"\ncolor-link constant.specialChar \"red\"\ncolor-link identi"
  },
  {
    "path": "runtime/colorschemes/sunny-day.micro",
    "chars": 810,
    "preview": "color-link default \"0,230\"\ncolor-link comment \"244\"\ncolor-link constant.string \"17\"\ncolor-link constant \"88\"\ncolor-link "
  },
  {
    "path": "runtime/colorschemes/twilight.micro",
    "chars": 1368,
    "preview": "# Twilight color scheme\ncolor-link default \"#F8F8F8,#141414\"\ncolor-link color-column \"#1B1B1B\"\ncolor-link comment \"#5F5A"
  },
  {
    "path": "runtime/colorschemes/zenburn.micro",
    "chars": 928,
    "preview": "color-link default \"188,237\"\ncolor-link comment \"108,237\"\ncolor-link constant.string \"174,237\"\ncolor-link constant.numbe"
  },
  {
    "path": "runtime/help/colors.md",
    "chars": 14380,
    "preview": "# Colors\n\nThis help page aims to cover two aspects of micro's syntax highlighting engine:\n\n* How to create colorschemes "
  },
  {
    "path": "runtime/help/commands.md",
    "chars": 7056,
    "preview": "# Command bar\n\nThe command bar is opened by pressing `Ctrl-e`. It is a single-line buffer,\nmeaning that all keybindings "
  },
  {
    "path": "runtime/help/copypaste.md",
    "chars": 6814,
    "preview": "Copy and paste are essential features in micro but can be\nconfusing to get right especially when running micro over SSH\n"
  },
  {
    "path": "runtime/help/defaultkeys.md",
    "chars": 9049,
    "preview": "# Default Keys\n\nBelow are simple charts of the default hotkeys and their functions. For more\ninformation about binding c"
  },
  {
    "path": "runtime/help/help.md",
    "chars": 2608,
    "preview": "# Micro help text\n\nMicro is an easy to use, intuitive, text editor that takes advantage of the\nfull capabilities of mode"
  },
  {
    "path": "runtime/help/keybindings.md",
    "chars": 19713,
    "preview": "# Keybindings\n\nMicro has a plethora of hotkeys that make it easy and powerful to use and all\nhotkeys are fully customiza"
  },
  {
    "path": "runtime/help/options.md",
    "chars": 26528,
    "preview": "# Options\n\nMicro stores all of the user configuration in its configuration directory.\n\nMicro uses `$MICRO_CONFIG_HOME` a"
  },
  {
    "path": "runtime/help/plugins.md",
    "chars": 22666,
    "preview": "# Plugins\n\nThis help topic is about creating plugins. If you need help installing or\nmanaging plugins, look for `plugin`"
  },
  {
    "path": "runtime/help/tutorial.md",
    "chars": 3725,
    "preview": "# Tutorial\n\nThis is a brief intro to micro's configuration system that will give some\nsimple examples showing how to con"
  },
  {
    "path": "runtime/plugins/autoclose/autoclose.lua",
    "chars": 2499,
    "preview": "VERSION = \"1.0.0\"\n\nlocal uutil = import(\"micro/util\")\nlocal utf8 = import(\"utf8\")\nlocal autoclosePairs = {\"\\\"\\\"\", \"''\", "
  },
  {
    "path": "runtime/plugins/comment/comment.lua",
    "chars": 7087,
    "preview": "VERSION = \"1.0.0\"\n\nlocal util = import(\"micro/util\")\nlocal config = import(\"micro/config\")\nlocal buffer = import(\"micro/"
  },
  {
    "path": "runtime/plugins/comment/help/comment.md",
    "chars": 1889,
    "preview": "# Comment Plugin\n\nThe comment plugin provides auto commenting/uncommenting.\nThe default binding to comment/uncomment a l"
  },
  {
    "path": "runtime/plugins/diff/diff.lua",
    "chars": 572,
    "preview": "VERSION = \"1.0.0\"\n\nlocal os = import(\"os\")\nlocal filepath = import(\"path/filepath\")\nlocal shell = import(\"micro/shell\")\n"
  },
  {
    "path": "runtime/plugins/ftoptions/ftoptions.lua",
    "chars": 388,
    "preview": "VERSION = \"1.0.0\"\n\nfunction onBufferOpen(b)\n    local ft = b:FileType()\n\n    if ft == \"go\" or\n    ft == \"makefile\" then\n"
  },
  {
    "path": "runtime/plugins/linter/help/linter.md",
    "chars": 3401,
    "preview": "# Linter\n\nThe linter plugin runs a compiler or linter on your source code\nand parses the resulting output so that the me"
  },
  {
    "path": "runtime/plugins/linter/linter.lua",
    "chars": 8713,
    "preview": "VERSION = \"1.0.0\"\n\nlocal micro = import(\"micro\")\nlocal runtime = import(\"runtime\")\nlocal filepath = import(\"path/filepat"
  },
  {
    "path": "runtime/plugins/literate/README.md",
    "chars": 226,
    "preview": "# Literate Micro\n\nSupport for reading `.lit` files from [zyedidia/Literate](https://github.com/zyedidia/Literate).\n\nThis"
  },
  {
    "path": "runtime/plugins/literate/literate.lua",
    "chars": 2018,
    "preview": "VERSION = \"1.0.0\"\n\nlocal config = import(\"micro/config\")\n\nfunction startswith(str, start)\n   return string.sub(str,1,str"
  },
  {
    "path": "runtime/plugins/status/help/status.md",
    "chars": 953,
    "preview": "# Status\n\nThe status plugin provides some functions for modifying the status line.\n\nUsing the `statusformatl` and `statu"
  },
  {
    "path": "runtime/plugins/status/status.lua",
    "chars": 1454,
    "preview": "VERSION = \"1.0.0\"\n\nlocal micro = import(\"micro\")\nlocal buffer = import(\"micro/buffer\")\nlocal config = import(\"micro/conf"
  },
  {
    "path": "runtime/runtime.go",
    "chars": 719,
    "preview": "package config\n\nimport (\n\t\"embed\"\n\t\"path/filepath\"\n\t\"strings\"\n)\n\n//go:generate go run syntax/make_headers.go syntax\n\n//g"
  },
  {
    "path": "runtime/runtime_test.go",
    "chars": 280,
    "preview": "package config\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestAssetDir(t *testing.T) {\n\tt.Paral"
  },
  {
    "path": "runtime/syntax/LICENSE",
    "chars": 1134,
    "preview": "Micro's syntax files are licensed under the MIT \"Expat\" License:\n\nCopyright (c) 2020: Zachary Yedidia, et al.\n\nPermissio"
  },
  {
    "path": "runtime/syntax/PowerShell.yaml",
    "chars": 5028,
    "preview": "# PowerShell syntax highlighting file for micro - https://micro-editor.github.io/\n# PowerShell syntax taken from: https:"
  },
  {
    "path": "runtime/syntax/README.md",
    "chars": 2155,
    "preview": "# Syntax Files\n\nHere are micro's syntax files.\n\nEach yaml file specifies how to detect the filetype based on file extens"
  },
  {
    "path": "runtime/syntax/ada.yaml",
    "chars": 1525,
    "preview": "filetype: ada\n\ndetect:\n    filename: \"(\\\\.ads$|\\\\.adb$|\\\\.ada$)\"\n\nrules:\n    # Operators\n    - symbol.operator: ([.:;,+*"
  },
  {
    "path": "runtime/syntax/apacheconf.yaml",
    "chars": 6527,
    "preview": "filetype: apacheconf\n\ndetect:\n    filename: \"httpd\\\\.conf|mime\\\\.types|vhosts\\\\.d\\\\\\\\*|\\\\.htaccess\"\n\nrules:\n    - identi"
  },
  {
    "path": "runtime/syntax/arduino.yaml",
    "chars": 2830,
    "preview": "filetype: ino\n\ndetect:\n    filename: \"\\\\.ino$\"\n\nrules:\n    - identifier: \"\\\\b[A-Z_][0-9A-Z_]+\\\\b\"\n\n      ## Sized (u)int"
  },
  {
    "path": "runtime/syntax/asciidoc.yaml",
    "chars": 1258,
    "preview": "filetype: asciidoc\n\ndetect:\n    filename: \"\\\\.(asc|asciidoc|adoc)$\"\n\nrules:\n    # main header\n    - preproc: \"^====+$\"\n "
  },
  {
    "path": "runtime/syntax/asm.yaml",
    "chars": 9887,
    "preview": "filetype: asm\n\ndetect:\n    filename: \"\\\\.(S|s|asm)$\"\n\nrules:\n    # This file is made mainly for NASM assembly\n\n    ## In"
  },
  {
    "path": "runtime/syntax/ats.yaml",
    "chars": 4075,
    "preview": "filetype: ATS\n\ndetect:\n    filename: \"\\\\.(d|h|s)ats$\"\n\nrules:\n    - default: \\b[[:alnum:]]+[^0-9A-Za-z]\n\n    # Operators"
  },
  {
    "path": "runtime/syntax/awk.yaml",
    "chars": 1499,
    "preview": "filetype: awk\n\ndetect:\n    filename: \"\\\\.awk$\"\n    header: \"^#!.*bin/(env +)?awk( |$)\"\n\nrules:\n    - preproc: \"\\\\$[A-Za-"
  },
  {
    "path": "runtime/syntax/b.yaml",
    "chars": 2806,
    "preview": "filetype: B\n\ndetect:\n    filename: '\\.b$'\n    # core control words + storage classes (Thompson B-ish)\n    signature: '\\b"
  },
  {
    "path": "runtime/syntax/bat.yaml",
    "chars": 4141,
    "preview": "filetype: batch\n\ndetect:\n  filename: \"(\\\\.bat$|\\\\.cmd$)\"\n\nrules:\n  # Numbers\n  - constant.number: \"\\\\b[0-9]+\\\\b\"\n  # Bra"
  },
  {
    "path": "runtime/syntax/c.yaml",
    "chars": 2880,
    "preview": "filetype: c\n\ndetect:\n    filename: \"(\\\\.(c|C)$|\\\\.(h|H)$|\\\\.ii?$|\\\\.(def)$)\"\n\nrules:\n    - identifier: \"\\\\b[A-Z_][0-9A-Z"
  },
  {
    "path": "runtime/syntax/caddyfile.yaml",
    "chars": 470,
    "preview": "filetype: caddyfile\n\ndetect:\n    filename: \"Caddyfile\"\n\nrules:\n    - identifier: \"^\\\\s*\\\\S+(\\\\s|$)\"\n    - type: \"^([\\\\w."
  },
  {
    "path": "runtime/syntax/cake.yaml",
    "chars": 158,
    "preview": "filetype: cake\ndetect:\n    filename: \"\\\\.cake$\"\n\nrules:\n    - include: \"csharp\"\n    - preproc: \"^[[:space:]]*#(addin|bre"
  },
  {
    "path": "runtime/syntax/clojure.yaml",
    "chars": 983,
    "preview": "filetype: clojure\n\ndetect:\n    filename: \"\\\\.(clj[sc]?|edn)$\"\n\nrules:\n\n    # Constants\n    - constant.bool: \"\\\\b(true|fa"
  },
  {
    "path": "runtime/syntax/cmake.yaml",
    "chars": 1181,
    "preview": "filetype: cmake\n\ndetect:\n    filename: \"(CMakeLists\\\\.txt|\\\\.cmake)$\"\n\nrules:\n    - identifier.var: \"^[[:space:]]*[A-Z0-"
  },
  {
    "path": "runtime/syntax/coffeescript.yaml",
    "chars": 2018,
    "preview": "filetype: coffeescript\n\ndetect:\n    filename: \"\\\\.coffee$\"\n\nrules:\n    - symbol.operator: \"([-+/*=<>!~%?:&|]|[.]{3})|\\\\b"
  },
  {
    "path": "runtime/syntax/colortest.yaml",
    "chars": 483,
    "preview": "filetype: colortest\n\ndetect:\n    filename: \"ColorTest$\"\n\nrules:\n    - black: \"\\\\bPLAIN\\\\b\"\n    - red: \"\\\\bred\\\\b\"\n    - "
  },
  {
    "path": "runtime/syntax/conky.yaml",
    "chars": 6343,
    "preview": "filetype: conky\n\ndetect:\n    filename: \"(\\\\.*conkyrc.*$|conky.conf)\"\n\nrules:\n    - type: \"\\\\b(alignment|append_file|back"
  },
  {
    "path": "runtime/syntax/cpp.yaml",
    "chars": 6202,
    "preview": "filetype: c++\n\ndetect:\n    filename: \"(\\\\.c(c|pp|xx)$|\\\\.h(h|pp|xx)?$|\\\\.ii?$|\\\\.(def)$)\"\n    signature: \"\\\\b(namespace|"
  },
  {
    "path": "runtime/syntax/crontab.yaml",
    "chars": 1489,
    "preview": "filetype: crontab\n\ndetect:\n    filename: \"crontab$|/tmp/crontab\\\\.\\\\w+$\"\n    header: \"^#.*?/etc/crontab\"\n\nrules:\n      #"
  },
  {
    "path": "runtime/syntax/crystal.yaml",
    "chars": 2136,
    "preview": "filetype: crystal\n\ndetect:\n    filename: \"\\\\.cr$\"\n\nrules:\n    # Asciibetical list of reserved words\n    - statement: \"\\\\"
  },
  {
    "path": "runtime/syntax/csharp.yaml",
    "chars": 2180,
    "preview": "filetype: csharp\n\ndetect:\n    filename: \"\\\\.cs$\"\n\nrules:\n    # Class\n    - identifier.class: \"class +[A-Za-z0-9]+ *((:) "
  },
  {
    "path": "runtime/syntax/css.yaml",
    "chars": 7080,
    "preview": "filetype: css\n\ndetect:\n    filename: \"\\\\.(css|scss)$\"\n\nrules:\n    # Classes and IDs\n    - statement: \"(?i).\"\n    # - nor"
  },
  {
    "path": "runtime/syntax/csx.yaml",
    "chars": 179,
    "preview": "filetype: csharp-script\ndetect:\n    filename: \"\\\\.csx$\"\n    header: \"^#!.*/(env +)?dotnet-script( |$)\"\n\nrules:\n    - inc"
  },
  {
    "path": "runtime/syntax/cuda.yaml",
    "chars": 2862,
    "preview": "filetype: cuda\n\ndetect:\n    filename: \"(\\\\.cu[h]?$)\"\n\nrules:\n    - identifier: \"\\\\b[A-Z_][0-9A-Z_]*\\\\b\"\n    - type: \"\\\\b"
  },
  {
    "path": "runtime/syntax/cython.yaml",
    "chars": 1323,
    "preview": "filetype: cython\n\ndetect:\n    filename: \"\\\\.pyx$|\\\\.pxd$|\\\\.pyi$\"\n\nrules:\n    # Python Keyword Color\n    - statement: \"\\"
  },
  {
    "path": "runtime/syntax/d.yaml",
    "chars": 4330,
    "preview": "filetype: d\n\ndetect:\n    filename: \"\\\\.(d(i|d)?)$\"\n\nrules:\n    # Operators and punctuation\n    - statement: \"(\\\\*|/|%|\\\\"
  },
  {
    "path": "runtime/syntax/dart.yaml",
    "chars": 1418,
    "preview": "filetype: dart\n\ndetect:\n    filename: \"\\\\.dart$\"\n\nrules:\n    - constant.number: \"\\\\b[-+]?([1-9][0-9]*|0[0-7]*|0x[0-9a-fA"
  },
  {
    "path": "runtime/syntax/default.yaml",
    "chars": 180,
    "preview": "filetype: unknown\n\ndetect:\n    filename: \"\"\n\nrules:\n    # Mails\n    - special: \"[[:alnum:].%_+-]+@[[:alnum:].-]+\"\n    # "
  },
  {
    "path": "runtime/syntax/dockerfile.yaml",
    "chars": 818,
    "preview": "filetype: dockerfile\n\ndetect:\n    filename: \"((Docker|Container)file[^/]*$|\\\\.(docker|container)file$)\"\n\nrules:\n    ## K"
  },
  {
    "path": "runtime/syntax/dot.yaml",
    "chars": 945,
    "preview": "filetype: dot\n\ndetect:\n    filename: \"\\\\.(dot|gv)$\"\n\nrules:\n    - type:   \"\\\\b(digraph|edge|graph|node|subgraph)\\\\b\"\n   "
  },
  {
    "path": "runtime/syntax/elixir.yaml",
    "chars": 1816,
    "preview": "filetype: elixir\n\ndetect:\n    filename: \"\\\\.ex$|\\\\.exs$\"\n\nrules:\n    - statement: \"\\\\b(abs|trunc|rem|div|round|max|min|a"
  },
  {
    "path": "runtime/syntax/elm.yaml",
    "chars": 924,
    "preview": "filetype: elm\n\ndetect:\n    filename: \"\\\\.elm$\"\n\nrules:\n    - statement: \"\\\\b(as|alias|case|else|exposing|if|import|in|le"
  },
  {
    "path": "runtime/syntax/erb.yaml",
    "chars": 2416,
    "preview": "filetype: erb\n\ndetect:\n    filename: \"\\\\.erb$|\\\\.rhtml$\"\n\nrules:\n    - error: \"<[^!].*?>\"\n    - symbol.tag: \"(?i)<[/]?(a"
  },
  {
    "path": "runtime/syntax/erlang.yaml",
    "chars": 2774,
    "preview": "filetype: erlang\n\ndetect:\n    filename: \"\\\\.erl$\"\n\nrules:\n    - identifier: \"\\\\b[A-Z][0-9a-z_]*\\\\b\"\n    # See: https://e"
  },
  {
    "path": "runtime/syntax/fish.yaml",
    "chars": 2044,
    "preview": "filetype: fish\n\ndetect:\n    filename: \"\\\\.fish$\"\n    header: \"^#!.*/(env +)?fish( |$)\"\n\nrules:\n      # Numbers\n    - con"
  },
  {
    "path": "runtime/syntax/forth.yaml",
    "chars": 827,
    "preview": "filetype: forth\n\ndetect:\n    filename: \"\\\\.(forth|4th|fs|fs8|ft|fth|frt)$\"\n\nrules:\n    - identifier: \"\\\\b[A-Za-z_0-9-]*\\"
  },
  {
    "path": "runtime/syntax/fortran.yaml",
    "chars": 2846,
    "preview": "filetype: fortran\n\ndetect:\n    filename: \"\\\\.([Ff]|[Ff]90|[Ff]95|[Ff][Oo][Rr])$\"\n\nrules:\n    - type:  \"(?i)\\\\b(action|ad"
  },
  {
    "path": "runtime/syntax/freebsd-kernel.yaml",
    "chars": 270,
    "preview": "filetype: freebsd-kernel\n\ndetect:\n    filename: \"GENERIC$\"\n\nrules:\n    - identifier: \"^(cpu|ident|options|makeoptions|de"
  },
  {
    "path": "runtime/syntax/fsharp.yaml",
    "chars": 1756,
    "preview": "filetype: fsharp\n\ndetect:\n    filename: \"\\\\.fs?$\"\n\nrules:\n    - identifier: \"\\\\b[A-Z][0-9a-z_]{2,}\\\\b\"\n      #declaratio"
  },
  {
    "path": "runtime/syntax/gdscript.yaml",
    "chars": 2347,
    "preview": "filetype: gdscript\n\ndetect:\n    filename: \"\\\\.gd$\"\n\nrules:\n    # Built-in constants\n    - constant: \"\\\\b(INF|NAN|PI|TAU)"
  },
  {
    "path": "runtime/syntax/gemini.yaml",
    "chars": 388,
    "preview": "filetype: gemini\n\ndetect:\n    filename: \"\\\\.(gmi|gemini)$\"\n\nrules:\n      # link lines\n    - constant: \"^=>[[:space:]].*\""
  },
  {
    "path": "runtime/syntax/gentoo-ebuild.yaml",
    "chars": 2202,
    "preview": "filetype: ebuild\n\ndetect:\n    filename: \"\\\\.e(build|class)$\"\n\nrules:\n    # All the standard portage functions\n    - iden"
  },
  {
    "path": "runtime/syntax/gentoo-etc-portage.yaml",
    "chars": 694,
    "preview": "filetype: etc-portage\n\ndetect:\n    filename: \"\\\\.(keywords|mask|unmask|use)(/.+)?$\"\n\nrules:\n    # Use flags:\n    - const"
  },
  {
    "path": "runtime/syntax/git-commit.yaml",
    "chars": 1194,
    "preview": "filetype: git-commit\n\ndetect:\n    filename: '^(.*[\\\\/])?(COMMIT_EDITMSG|TAG_EDITMSG|MERGE_MSG)$'\n\nrules:\n    # File chan"
  }
]

// ... and 128 more files (download for full content)

About this extraction

This page contains the full source code of the micro-editor/micro GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 328 files (1.2 MB), approximately 375.3k tokens, and a symbol index with 1331 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!