[
  {
    "path": ".busted",
    "content": "return {\n  default = {\n    verbose = true,\n    lpath = \"./lua/?.lua;./lua/?/init.lua\"\n  }\n}\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\n\ngithub: # []\npatreon: # Replace with a single Patreon username\nopen_collective: # Replace with a single Open Collective username\nko_fi: # Replace with a single Ko-fi username\ntidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel\ncommunity_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry\nliberapay: # Replace with a single Liberapay username\nissuehunt: # Replace with a single IssueHunt username\notechie: # Replace with a single Otechie username\ncustom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']\n"
  },
  {
    "path": ".gitignore",
    "content": "*.py[eco]\n__pycache__/\nMakefile\ndoc/tags\n"
  },
  {
    "path": ".semaphore/semaphore.yml",
    "content": "version: v1.0\nname: Initial Pipeline\nagent:\n  machine:\n    type: e1-standard-2\n    os_image: ubuntu2004\nblocks:\n  - name: Set-up\n    task:\n      jobs:\n        - name: Lint\n          commands:\n            - checkout\n            - sudo apt-get update\n            - sudo apt-get install -y lua-check\n            - luacheck lua/* --formatter JUnit > ./report.xml\n      epilogue:\n        on_fail:\n          commands:\n            - '[[ -f report.xml ]] && test-results publish report.xml'\n"
  },
  {
    "path": "LICENSE",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2018, Henry John Kupty\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the copyright holder nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# iron.nvim\n\nInteractive Repls Over Neovim.\n\n## What is iron.nvim\n\n[![asciicast](https://asciinema.org/a/495376.svg)](https://asciinema.org/a/495376)\nIron allows you to quickly interact with the repl without having to leave your\nwork buffer\n\nIt both a plugin and a library, allowing for better user experience and\nextensibility at the same time.\n\n## How to install\n\nUsing [packer.nvim](https://github.com/wbthomason/packer.nvim) \n(or the plugin manager of your choice):\n\n```lua\n  use {'Vigemus/iron.nvim'}\n```\n\n## How to configure\n\nBelow is a very simple configuration for iron:\n\n```lua\nlocal iron = require(\"iron.core\")\nlocal view = require(\"iron.view\")\nlocal common = require(\"iron.fts.common\")\n\niron.setup {\n  config = {\n    -- Whether a repl should be discarded or not\n    scratch_repl = true,\n    -- Your repl definitions come here\n    repl_definition = {\n      sh = {\n        -- Can be a table or a function that\n        -- returns a table (see below)\n        command = {\"zsh\"}\n      },\n      python = {\n        command = { \"python3\" },  -- or { \"ipython\", \"--no-autoindent\" }\n        format = common.bracketed_paste_python,\n        block_dividers = { \"# %%\", \"#%%\" },\n        env = {PYTHON_BASIC_REPL = \"1\"} --this is needed for python3.13 and up.\n      }\n    },\n    -- set the file type of the newly created repl to ft\n    -- bufnr is the buffer id of the REPL and ft is the filetype of the \n    -- language being used for the REPL. \n    repl_filetype = function(bufnr, ft)\n      return ft\n      -- or return a string name such as the following\n      -- return \"iron\"\n    end,\n    -- Send selections to the DAP repl if an nvim-dap session is running.\n    dap_integration = true,\n    -- How the repl window will be displayed\n    -- See below for more information\n    repl_open_cmd = view.bottom(40),\n\n    -- repl_open_cmd can also be an array-style table so that multiple \n    -- repl_open_commands can be given.\n    -- When repl_open_cmd is given as a table, the first command given will\n    -- be the command that `IronRepl` initially toggles.\n    -- Moreover, when repl_open_cmd is a table, each key will automatically\n    -- be available as a keymap (see `keymaps` below) with the names \n    -- toggle_repl_with_cmd_1, ..., toggle_repl_with_cmd_k\n    -- For example,\n    -- \n    -- repl_open_cmd = {\n    --   view.split.vertical.rightbelow(\"%40\"), -- cmd_1: open a repl to the right\n    --   view.split.rightbelow(\"%25\")  -- cmd_2: open a repl below\n    -- }\n\n  },\n  -- Iron doesn't set keymaps by default anymore.\n  -- You can set them here or manually add keymaps to the functions in iron.core\n  keymaps = {\n    toggle_repl = \"<space>rr\", -- toggles the repl open and closed.\n    -- If repl_open_command is a table as above, then the following keymaps are\n    -- available\n    -- toggle_repl_with_cmd_1 = \"<space>rv\",\n    -- toggle_repl_with_cmd_2 = \"<space>rh\",\n    restart_repl = \"<space>rR\", -- calls `IronRestart` to restart the repl\n    send_motion = \"<space>sc\",\n    visual_send = \"<space>sc\",\n    send_file = \"<space>sf\",\n    send_line = \"<space>sl\",\n    send_paragraph = \"<space>sp\",\n    send_until_cursor = \"<space>su\",\n    send_mark = \"<space>sm\",\n    send_code_block = \"<space>sb\",\n    send_code_block_and_move = \"<space>sn\",\n    mark_motion = \"<space>mc\",\n    mark_visual = \"<space>mc\",\n    remove_mark = \"<space>md\",\n    cr = \"<space>s<cr>\",\n    interrupt = \"<space>s<space>\",\n    exit = \"<space>sq\",\n    clear = \"<space>cl\",\n  },\n  -- If the highlight is on, you can change how it looks\n  -- For the available options, check nvim_set_hl\n  highlight = {\n    italic = true\n  },\n  ignore_blank_lines = true, -- ignore blank lines when sending visual select lines\n}\n\n-- iron also has a list of commands, see :h iron-commands for all available commands\nvim.keymap.set('n', '<space>rf', '<cmd>IronFocus<cr>')\nvim.keymap.set('n', '<space>rh', '<cmd>IronHide<cr>')\n```\n\nThe repl `command` can also be a function:\n\n```lua\niron.setup{\n  config = {\n    repl_definition = {\n      -- custom repl that loads the current file\n      haskell = {\n        command = function(meta)\n          local filename = vim.api.nvim_buf_get_name(meta.current_bufnr)\n          return { 'cabal', 'v2-repl', filename}\n        end\n      }\n    },\n  },\n}\n```\n\n### REPL windows\n\niron.nvim supports both splits and floating windows and has helper functions\nfor opening new repls in either of them:\n\n#### For splits\n\nIf you prefer using splits to your repls, iron provides a few utility functions\nto make it simpler:\n\n```lua\nlocal view = require(\"iron.view\")\n\n-- iron.setup {...\n\n-- One can always use the default commands from vim directly\nrepl_open_cmd = \"vertical botright 80 split\"\n\n-- But iron provides some utility functions to allow you to declare that dynamically,\n-- based on editor size or custom logic, for example.\n\n-- Vertical 50 columns split\n-- Split has a metatable that allows you to set up the arguments in a \"fluent\" API\n-- you can write as you would write a vim command.\n-- It accepts:\n--   - vertical\n--   - leftabove/aboveleft\n--   - rightbelow/belowright\n--   - topleft\n--   - botright\n-- They'll return a metatable that allows you to set up the next argument\n-- or call it with a size parameter\nrepl_open_cmd = view.split.vertical.botright(50)\n\n-- If the supplied number is a fraction between 1 and 0,\n-- it will be used as a proportion\nrepl_open_cmd = view.split.vertical.botright(0.61903398875)\n\n-- The size parameter can be a number, a string or a function.\n-- When it's a *number*, it will be the size in rows/columns\n-- If it's a *string*, it requires a \"%\" sign at the end and is calculated\n-- as a percentage of the editor size\n-- If it's a *function*, it should return a number for the size of rows/columns\n\nrepl_open_cmd = view.split(\"40%\")\n\n-- You can supply custom logic\n-- to determine the size of your\n-- repl's window\nrepl_open_cmd = view.split.topleft(function()\n  if some_check then\n    return vim.o.lines * 0.4\n  end\n  return 20\nend)\n\n-- An optional set of options can be given to the split function if one\n-- wants to configure the window behavior.\n-- Note that, by default `winfixwidth` and `winfixheight` are set\n-- to `true`. If you want to overwrite those values,\n-- you need to specify the keys in the option map as the example below\n\nrepl_open_cmd = view.split(\"40%\", {\n  winfixwidth = false,\n  winfixheight = false,\n  -- any window-local configuration can be used here\n  number = true\n})\n```\n\n#### For floats\n\nIf you prefer floats, the API is the following:\n\n```lua\nlocal view = require(\"iron.view\")\n\n-- iron.setup {...\n\n-- The same size arguments are valid for float functions\nrepl_open_cmd = view.top(\"10%\")\n\n-- `view.center` takes either one or two arguments\nrepl_open_cmd = view.center(\"30%\", 20)\n\n-- If you supply only one, it will be used for both dimensions\n-- The function takes an argument to whether the orientation is vertical(true) or\n-- horizontal (false)\nrepl_open_cmd = view.center(function(vertical)\n-- Useless function, but it will be called twice,\n-- once for each dimension (width, height)\n  if vertical then\n    return 50\n  end\n  return 20\nend)\n\n-- `view.offset` allows you to control both the size of each dimension and\n-- the distance of them from the top-left corner of the screen\nrepl_open_cmd = view.offset{\n  width = 60,\n  height = vim.o.height * 0.75\n  w_offset = 0,\n  h_offset = \"5%\"\n}\n\n-- Some helper functions allow you to calculate the offset\n-- in relation to the size of the window.\n-- While all other sizing functions take only the orientation boolean (vertical or not),\n-- for offsets, the functions will also take the repl size in that dimension\n-- as argument. The helper functions then return a function that takes two arguments\n-- to calculate the offset\nrepl_open_cmd = view.offset{\n  width = 60,\n  height = vim.o.height * 0.75\n  -- `view.helpers.flip` will subtract the size of the REPL\n  -- window from the total dimension, then apply an offset.\n  -- Effectively, it flips the top/left to bottom/right orientation\n  w_offset = view.helpers.flip(2),\n  -- `view.helpers.proportion` allows you to apply a relative\n  -- offset considering the REPL window size.\n  -- for example, 0.5 will centralize the REPL in that dimension,\n  -- 0 will pin it to the top/left and 1 will pin it to the bottom/right.\n  h_offset = view.helpers.proportion(0.5)\n}\n\n-- Differently from `view.center`, all arguments are required\n-- and no defaults will be applied if something is missing.\nrepl_open_cmd = view.offset{\n  width = 60,\n  height = vim.o.height * 0.75\n  -- Since we know we're using this function in the width offset\n  -- calculation, we can ignore the argument\n  w_offset = function(_, repl_size)\n    -- Ideally this function calculates a value based on something..\n    return 42\n  end,\n  h_offset = view.helpers.flip(2)\n}\n```\n"
  },
  {
    "path": "bin/pctl",
    "content": "#!/bin/bash\nset -eou pipefail\n\nBIN_DIR=\"$(dirname \"$(realpath \"$0\")\")\"\nROOT_DIR=\"$(dirname \"$BIN_DIR\")\"\n\nLUAROCKS=\"luarocks-5.1\"\n\nexists() {\n  command -v \"$1\" > /dev/null\n}\n\nsetup(){\n  exists luarocks-5.1 || {\n    exists luarocks && {\n      LUAROCKS=\"luarocks --lua-version 5.1\"\n    } || {\n      echo 'Please install luarocks'\n      exit 1\n    }\n  }\n\n  $LUAROCKS --local install \"$1\"\n}\n\ntests(){\n  exists busted || setup busted\n  busted\n}\n\nlinter(){\n  exists luacheck || setup luacheck\n  luacheck lua/\n}\n\nrun() {\n  tests\n  linter\n}\n\n\nrun-dev(){\ninotifywait -r -q -m -e close_write --format %e lua spec | while read -r ; do\nbusted\ndone\n}\n\ncd $ROOT_DIR && \"$@\"\n"
  },
  {
    "path": "doc/iron.txt",
    "content": "*iron.nvim* Interactive Repls Over Neovim\n\n===============================================================================\nCONTENTS                                                            *iron-help*\n\n  Introduction............................|iron-introduction|\n  Awesomeness.............................|iron-awesomeness|\n  Languages...............................|iron-languages|\n  Commands................................|iron-commands|\n  Functions...............................|iron-functions|\n  Customizing.............................|iron-customizing|\n  Mappings................................|iron-mappings|\n  Extending...............................|iron-extending|\n  Credits.................................|iron-credits|\n\n===============================================================================\nIntroduction                                                *iron-introduction*\n\nIron is a helper plugin that allows you to manage and interact with live\nRead-Eval-Print-Loops (REPLs) directly from Neovim, through terminal buffers.\nIron mostly interacts with plugins via stdin/stdout, with few exceptions.\n\n===============================================================================\nAwesomeness                                                  *iron-awesomeness*\n\nIron makes it very easy to focus on the code while interacting with the REPL.\nIt allows you to, seamlessly, send chunks of code directly into the REPL,\nwithout disrupting your coding workflow.\n\nA lot more can be accomplished through Iron. In order to add new functionality\n(such as running tests, evaluating expressions, adding new keybindings, etc),\nall it takes is to extend the REPL providers.\n\n===============================================================================\nLanguages                                                      *iron-languages*\n\nCurrently, Iron has support for the following programming languages:\n\n  - clojure\n    - boot\n    - lein\n  - cpp\n    - root https://root.cern.ch/\n  - csh\n    - csh\n    - tcsh\n  - elixir\n  - elm\n  - erlang\n  - fennel\n  - fish\n  - forth\n  - haskell\n    - intero\n    - stack ghci\n    - cabal repl\n    - ghci\n  - hylang\n  - javascript\n  - julia\n  - lisp\n    - sbcl\n    - clisp\n  - lua\n  - ocaml\n    - ocamltop\n    - utop\n  - php\n    - php\n    - psysh\n  - prolog\n    - gprolog\n    - swipl\n  - ps1 (powershell)\n  - pure-lang\n  - python\n    - python\n    - ipython\n    - ptpython\n    - ptipython\n  - r\n  - racket\n  - ruby\n  - scala\n    - scala\n    - sbt\n  - scheme\n    - guile\n    - csi\n  - sh\n    - zsh\n    - bash\n    - sh\n  - stata\n  - tcl\n  - typescript\n  - zsh\n\n===============================================================================\nCommands                                                        *iron-commands*\n\nIron provides the following commands for interacting with REPLs:\n\n:IronRepl [ft]\n  Open a REPL for current or given file type.\n\n:IronReplHere [ft]\n  Open a REPL for current or given file type in the current window.\n\n:IronRestart\n  Restart the current REPL.\n\n:IronSend[!] some [text...]\n  Sends the supplied chunk of text to the repl for current filetype.\n  If used with a `!`, the first argument is the filetype\n  This allows for invoking a new repl immediately:\n      > :IronSend! python print(20 * 32)\n\n:IronFocus [ft]\n  Focuses on the repl for current or given file type.\n\n:IronHide [ft]\n  Hide the repl window for current or given file type.\n\n:IronWatch file|mark\n  send the file/mark to the repl after writing the buffer\n\n:IronAttach ft\n  Attach current buffer regardless of its filetype to a repl\n\n===============================================================================\nFunctions                                                      *iron-functions*\n\nIron is a lua plugin so all its functionality is exposed through lua\nfunctions.\n\nThe code is mainly divided in two major namespaces:\n- `iron.core`, for most user-facing functions and\n- `iron.lowlevel` for the functions that interact with the repl directly\n\nThe code is well documented, so we'll skip `iron.lowlevel` in this doc.\n\nBelow are the core functions:\n\n* core.repl_here(ft)         Creates a repl in the same window\n\n* core.repl_restart()        Restarts the repl in the current window or for\n                             the current buffer's filetype\n\n* core.close_repl(ft)        Closes the repl for supplied filetype\n\n* core.repl_for(ft)          Creates a repl for given filetype in a new window\n\n* core.focus_on(ft)          Moves to (or creates) the repl for given filetype\n\n* core.send(ft, data)        Sends data (a table) to the repl for given\n                             filetype\n\n* core.send_code_block(move) Sends the lines between two code_dividers as\n                             defined in repl_definition or end and start of\n                             buffer to the repl. If move is true, the cursor\n                             is moved to next code block. If move is false,\n                             the cursor position is unchanged.\n\n* core.send_file()           Sends the whole file to the repl\n\n* core.send_line()           Sends line below the cursor to the repl\n\n* core.send_until_cursor()   Sends the buffer from the start until the line\n                             where the cursor is (inclusive) to the repl\n\n* core.send_motion(motion)   Applies given motion and sends the result to the\n                             repl. See `send_motion` in |iron-mappings|\n\n* core.send_mark()           Sends the marked chunk\n\n* core.mark_visual()         Adds a mark around the visual selection\n\n* core.mark_motion()         Adds a mark around the motion object\n\n* core.watch(handler, bufnr) Watches for saves in the supplied buffer\n\n* core.unwatch(bufnr)        Removes the watch on the supplied buffer\n\n* core.setup(config)         Configures iron. See |iron-customizing|\n\nFor more information, check the luadocs in the functions.\n\n===============================================================================\nCustomizing                                                  *iron-customizing*\n\nIron is configured through `core.setup`\n\nBelow is a sample config:\n\n```\nlocal iron = require(\"iron.core\")\n\niron.setup{\n  config = {\n    -- Highlights the last sent block with bold\n    highlight_last = \"IronLastSent\",\n\n    -- Toggling behavior is on by default.\n    -- Other options are: `single` and `focus`\n    visibility = require(\"iron.visibility\").toggle,\n\n    -- Scope of the repl\n    -- By default it is one for the same `pwd`\n    -- Other options are `tab_based` and `singleton`\n    scope = require(\"iron.scope\").path_based,\n\n    -- Whether the repl buffer is a \"throwaway\" buffer or not\n    scratch_repl = false,\n\n    -- Automatically closes the repl window on process end\n    close_window_on_exit = true,\n    repl_definition = {\n     -- forcing a default\n      python = require(\"iron.fts.python\").ipython\n\n     -- new, custom repl\n      lua = {\n        -- Can be a table or a function that returns a table (see below)\n        command = {\"my-lua-repl\", \"-arg\"}\n      }\n     -- setting up code_dividers for core.send_code_block\n      python = {\n        command = { \"python3\" }, -- or { \"ipython\", \"--no-autoindent\" }\n        format = require(\"iron.fts.common\").bracketed_paste_python,\n        block_dividers = { \"# %%\", \"#%%\" },\n      }\n    },\n    -- Whether iron should map the `<plug>(..)` mappings\n    should_map_plug = true,\n\n    -- Repl position. Check `iron.view` for more options,\n    -- currently there are four positions: left, right, bottom, top,\n    -- the param is the width/height of the float window\n    repl_open_cmd = require(\"iron.view\").curry.bottom(40),\n    -- Alternatively, pass a function, which is evaluated when a repl is open.\n    repl_open_cmd = require('iron.view').curry.right(function()\n        return vim.o.columns / 2\n    end),\n    -- iron.view.curry will open a float window for the REPL.\n    -- alternatively, pass a string of vimscript for opening a fixed window:\n    repl_open_cmd = 'belowright 15 split',\n\n    -- If the repl buffer is listed\n    buflisted = false,\n  },\n\n  -- All the keymaps are set individually\n  -- Below is a suggested default\n  keymaps = {\n    send_motion = \"<space>sc\",\n    visual_send = \"<space>sc\",\n    send_file = \"<space>sf\",\n    send_line = \"<space>sl\",\n    send_until_cursor = \"<space>su\",\n    send_mark = \"<space>sm\",\n    send_code_block = \"<space>sb\",\n    send_code_block_and_move = \"<space>sn\",\n    mark_motion = \"<space>mc\",\n    mark_visual = \"<space>mc\",\n    remove_mark = \"<space>md\",\n    cr = \"<space>s<cr>\",\n    interrupt = \"<space>s<space>\",\n    exit = \"<space>sq\",\n    clear = \"<space>cl\",\n  },\n\n  -- If the highlight is on, you can change how it looks\n  -- For the available options, check nvim_set_hl\n  highlight = {\n    italic = true\n  }\n}\n```\n\nThe repl command can also be a function:\n\n```\niron.setup{\n  config = {\n    repl_definition = {\n      -- custom repl that loads the current file\n      haskell = {\n        command = function(meta)\n          local filename = vim.api.nvim_buf_get_name(meta.current_bufnr)\n          return { 'cabal', 'v2-repl', filename}\n        end\n      }\n    },\n  },\n}\n```\n\n===============================================================================\nMappings                                                        *iron-mappings*\n\nIron by default doesn't map the keybindings, only those supplied in the\ncore.setup function.\n\n- send_motion: Sends a motion to the repl\n- visual_send: Sends the visual selection to the repl\n- send_file: Sends the whole file to the repl\n- send_line: Sends the line below the cursor to the repl\n- send_until_cursor: Sends the buffer from the start until the line where the\n  cursor is (inclusive) to the repl\n- send_mark: Sends the text within the mark\n- send_code_block: Sends the text between two code dividers\n- send_code_block_and_move: Sends the text between two code dividers and move\n  to next code block\n- mark_motion: Marks the text object\n- mark_visual: Marks the visual selection\n- remove_mark: Removes the set mark\n- cr: Sends a return to the repl\n- interrupt: Sends a `<C-c>` signal to the repl\n- exit: Exits the repl\n- clear: Clears the repl window\n\n===============================================================================\nExtending                                                      *iron-extending*\n\nIron provides some modules that can be used on your configuration to change\nthe behavior:\n\n* `iron.memory_management`:\n  It provides three memory management modes for your repls:\n  * `tab_based`:\n    It saves all the variables based on your tab, so new tabs create new\n    repls.\n  * `path_based` (default):\n    It saves all the variables according to your base path (pwd),\n    so changing the cd/tcd/lcd will create new repls.\n  * `singleton`:\n    It will never create two repls for the same filetype.\n\n* `iron.visibility`:\n  It changes the behavior on how iron deals with windows for the repl.\n  * `single`:\n    Ensures that a window exists and shows it;\n  * `toggle` (default):\n    Alternates between opening and closing the window\n  * `focus`:\n    Moves the focus to the repl window.\n\n* `iron.view`:\n  Creates the windows.\n  Subject to change for the moment. Please refer to the README while the API\n  is still unstable.\n\n===============================================================================\nCredits                                                          *iron-credits*\n\nPlugin created by Henry Kupty <hkupty@gmail.com>.\nIt is free to use and extend. Please consider opening a pull request if\nextended.\n\nSource at https://github.com/Vigemus/iron.nvim\n\n vim:tw=78:ft=help:norl:\n"
  },
  {
    "path": "lua/iron/config.lua",
    "content": "-- luacheck: globals vim\nlocal view = require(\"iron.view\")\n\n--- Default values\n--@module config\nlocal config\n\n--- Default configurations for iron.nvim\n-- @table config.values\n-- @tfield false|string highlight_last Either false or the name of a highlight group\n-- @field scratch_repl When enabled, the repl buffer will be a scratch buffer\n-- @field should_map_plug when enabled iron will provide its mappings as `<plug>(..)` as well,\n-- for backwards compatibility\n-- @field close_window_on_exit closes repl window on process exit\nlocal values = {\n  highlight_last = \"IronLastSent\",\n  visibility = require(\"iron.visibility\").toggle,\n  scope = require(\"iron.scope\").path_based,\n  scratch_repl = false,\n  close_window_on_exit = true,\n  preferred = setmetatable({}, {\n    __newindex = function(tbl, k, v)\n      vim.deprecate(\"config.preferred\", \"config.repl_definition\", \"3.1\", \"iron.nvim\")\n      rawset(tbl, k, v)\n    end\n  }),\n  repl_definition = setmetatable({}, {\n    __index = function(tbl, key)\n      local repl_definitions = require(\"iron.fts\")[key]\n      local repl_def\n      for _, v in pairs(repl_definitions) do\n        if vim.fn.executable(v.command[1]) == 1 then\n          repl_def = v\n          break\n        end\n      end\n      if repl_def == nil then\n        error(\"Failed to locate REPL executable, aborting\")\n      else\n        rawset(tbl, key, repl_def)\n        return repl_def\n      end\n    end\n  }),\n  repl_filetype = function(bufnr, ft)\n    return \"iron\"\n  end,\n  should_map_plug = false,\n  repl_open_cmd = view.split.botright(40),\n  current_view = 1,\n  views = {\n    view.bottom(40)\n  },\n  mark = { -- Arbitrary numbers\n    save_pos = 20,\n    send = 77,\n  },\n  buflisted = false,\n  ignore_blank_lines = true,\n}\n\n-- HACK for LDoc to correctly link @see annotations\nconfig = vim.deepcopy(values)\nconfig.values = values\n\nreturn config\n"
  },
  {
    "path": "lua/iron/core.lua",
    "content": "-- luacheck: globals vim unpack\n\nlocal log = require(\"iron.log\")\nlocal ll = require(\"iron.lowlevel\")\nlocal focus = require(\"iron.visibility\").focus\nlocal config = require(\"iron.config\")\nlocal marks = require(\"iron.marks\")\nlocal is_windows = require(\"iron.util.os\").is_windows\nlocal view = require(\"iron.view\")\nlocal dap = require(\"iron.dap\")\n\nlocal autocmds = {}\n\n--- Core functions of iron\n-- @module core\nlocal core = {}\n\n--- Local helpers for creating a new repl.\n-- Should be used by core functions, but not\n-- exposed to the end-user\n-- @local\nlocal new_repl = {}\n\n--- Create a new repl on the current window\n-- Simple wrapper around the low level functions\n-- Useful to avoid rewriting the get_def + create + save pattern\n-- @param ft filetype\n-- @param bufnr buffer to be used.\n-- @param current_bufnr current buffer.\n-- @tparam cleanup function Function to cleanup if call fails\n-- @return saved snapshot of repl metadata\nnew_repl.create = function(ft, bufnr, current_bufnr, cleanup)\n  local meta\n  local success, repl = pcall(ll.get_repl_def, ft)\n\n  if not success and cleanup ~= nil then\n    cleanup()\n    error(repl)\n  end\n\n  success, meta = pcall(\n    ll.create_repl_on_current_window,\n    ft, repl, bufnr, current_bufnr\n  )\n  if success then\n    ll.set(ft, meta)\n\n    local filetype = config.repl_filetype(bufnr, ft)\n    if filetype ~= nil then\n      vim.api.nvim_set_option_value(\"filetype\", filetype, { buf = bufnr })\n    end\n\n    return meta\n  elseif cleanup ~= nil then\n    cleanup()\n  end\n\n\n  error(meta)\nend\n\n--- Create a new repl on a new repl window\n-- Adds a layer on top of @{new_repl.create},\n-- ensuring it is created on a new window\n-- @param ft filetype\n-- @return saved snapshot of repl metadata\nnew_repl.create_on_new_window = function(ft)\n  local current_bufnr = vim.api.nvim_get_current_buf()\n  local bufnr = ll.new_buffer()\n\n  local replwin = ll.new_window(bufnr)\n  vim.api.nvim_set_current_win(replwin)\n  local meta = new_repl.create(ft, bufnr, current_bufnr, function()\n    vim.api.nvim_win_close(replwin, true)\n    vim.api.nvim_buf_delete(bufnr, { force = true })\n  end)\n\n  return meta\nend\n\n--- Creates a repl in the current window\n-- @param ft the filetype of the repl to be created\n-- @treturn table metadata of the repl\ncore.repl_here = function(ft)\n  local meta = ll.get(ft)\n  if ll.repl_exists(meta) then\n    vim.api.nvim_set_current_buf(meta.bufnr)\n    return meta\n  else\n    local current_bufnr = vim.api.nvim_get_current_buf()\n    local bufnr = ll.new_buffer()\n    return new_repl.create(ft, bufnr, current_bufnr, function()\n      vim.api.nvim_buf_delete(bufnr, { force = true })\n    end)\n  end\nend\n\n--- Restarts the repl for the current buffer\n-- First, check if the cursor is on top or a REPL\n-- Then, start a new REPL of the same type and enter it into the window\n-- Afterwards, wipe out the old REPL buffer\n-- This is done without asking for confirmation, so user beware\n-- @todo Split into \"restart a repl\" and \"do X for current buffer's repl\"\n-- @return saved snapshotof repl metadata\ncore.repl_restart = function()\n  local bufnr_here = vim.fn.bufnr(\"%\")\n  local ft = ll.get_repl_ft_for_bufnr(bufnr_here)\n  local current_bufnr = vim.api.nvim_get_current_buf()\n\n  if ft ~= nil then\n    local bufnr = ll.new_buffer()\n\n    local meta = new_repl.create(\n      ft, bufnr, current_bufnr,\n      function()\n        vim.api.nvim_buf_delete(bufnr, { force = true })\n      end\n    )\n\n    -- created a new one, now have to kill the old one\n    vim.api.nvim_buf_delete(bufnr_here, { force = true })\n    return meta\n  else\n    ft = ll.get_buffer_ft(0)\n\n    local meta = ll.get(ft)\n    if ll.repl_exists(meta) then\n      local replwin = vim.fn.bufwinid(meta.bufnr)\n      local currwin = vim.api.nvim_get_current_win()\n      local new_meta\n\n      if replwin == nil or replwin == -1 then\n        new_meta = new_repl.create_on_new_window(ft)\n      else\n        vim.api.nvim_set_current_win(replwin)\n        local bufnr = ll.new_buffer()\n        new_meta = new_repl.create(\n          ft, bufnr, current_bufnr,\n          function()\n          vim.api.nvim_buf_delete(bufnr, {force = true})\n          end\n        )\n      end\n\n      vim.api.nvim_set_current_win(currwin)\n      vim.api.nvim_buf_delete(meta.bufnr, { force = true })\n\n      return new_meta\n    else\n      error('No repl found in current buffer; cannot restart')\n    end\n  end\nend\n\n--- Sends a close request to the repl\n-- if @{config.values.close_window_on_exit} is set to true,\n-- all windows associated with that repl will be closed.\n-- Otherwise, this will only finish the process.\n-- @param ft filetype\ncore.close_repl = function(ft)\n  -- see the similar logic on core.send to see how the REPLs created by\n  -- core.attach is handled.\n  local meta = vim.b[0].repl\n\n  if not meta or not ll.repl_exists(meta) then\n    ft = ft or ll.get_buffer_ft(0)\n    meta = ll.get(ft)\n  end\n\n  if not ll.repl_exists(meta) then\n    return\n  end\n\n  ll.send_to_repl(meta, string.char(04))\nend\n\n--- Hides the repl windows for a given filetype\n-- @param ft filetype\ncore.hide_repl = function(ft)\n  ft = ft or ll.get_buffer_ft(0)\n  local meta = ll.get(ft)\n\n  if ll.repl_exists(meta) then\n    local window = vim.fn.bufwinid(meta.bufnr)\n    if window ~= -1 then\n      vim.api.nvim_win_hide(window)\n    end\n  end\nend\n\n--- Creates a repl for a given filetype\n-- It should open a new repl on a new window for the filetype\n-- supplied as argument.\n-- @param ft filetype\ncore.repl_for = function(ft)\n  if dap.is_dap_session_running() then\n    -- If there's a dap session running, default to the dap repl. By\n    -- intercepting here, we can support dap repls in filetypes that aren't\n    -- normally supported (e.g. java).\n    -- TODO find and open the dap repl window?\n    return\n  end\n  local meta = ll.get(ft)\n  if ll.repl_exists(meta) then\n    local currwin = vim.api.nvim_get_current_win()\n    config.visibility(meta.bufnr, function()\n      local winid = ll.new_window(meta.bufnr)\n      vim.api.nvim_win_set_buf(winid, meta.bufnr)\n      vim.api.nvim_set_current_win(currwin)\n      return winid\n    end)\n    return meta\n  else\n    local currwin = vim.api.nvim_get_current_win()\n    meta = new_repl.create_on_new_window(ft)\n    vim.api.nvim_set_current_win(currwin)\n    return meta\n  end\nend\n\n--- Moves to the repl for given filetype\n-- When it doesn't exist, a new repl is created\n-- directly moving the focus to it.\n-- @param ft filetype\ncore.focus_on = function(ft)\n  local meta = ll.get(ft)\n  if ll.repl_exists(meta) then\n    focus(meta.bufnr, function()\n      local winid = ll.new_window(meta.bufnr)\n      vim.api.nvim_win_set_buf(winid, meta.bufnr)\n      return winid\n    end)\n    return meta\n  else\n    return new_repl.create_on_new_window(ft)\n  end\nend\n\n--- Sends data to the repl\n-- This is a top-level wrapper over the low-level\n-- functions. It should send data to the repl, ensuring\n-- it exists.\n-- @param ft filetype (will be inferred if not supplied)\n-- @tparam string|table data data to be sent to the repl.\nlocal send = function(ft, data)\n  -- the buffer local variable `repl` is created by core.attach function to\n  -- track non-default REPls.\n  local meta = vim.b[0].repl\n\n  if dap.is_dap_session_running() then\n    dap.send_to_dap(data)\n    return\n  end\n\n  -- However, this attached meta may associated with a REPL that has been\n  -- closed, we need to check for that.\n  -- If the attached REPL is not existed or has been closed, we will try to\n  -- get the REPL meta based on the ft of current buffer.\n  if not meta or not ll.repl_exists(meta) then\n    ft = ft or ll.get_buffer_ft(0)\n    if data == nil then return end\n    meta = ll.get(ft)\n  end\n\n  -- If the repl doesn't exist, it will be created\n  if not ll.repl_exists(meta) then\n    meta = core.repl_for(ft)\n  end\n  ll.send_to_repl(meta, data)\nend\n\n\n-- TODO fix this hack fix that allows ipython with Windows OS\n-- To fix this, there needs to be some sort of check on the progress of the\n-- call to vim.fn.chansend(meta.job, dt) inside of ll.send_to_repl. The defer\n-- is here to ensure that sending of string.char(13) sends after the commands\n-- are finished sending to the ipython REPL\ncore.send = function(ft, data)\n  if not is_windows() then\n    send(ft, data)\n  else\n    send(ft, data)\n\n    -- This is a hack fix that allows windows ipython to run the commands sent\n    -- to the repl. However, the same issue will arise as before (the command sent\n    -- to the repl but the code not running) if many lines are sent to the ipython\n    -- repl (many as in more than 150 milliseconds worth). It appear that windows\n    -- and powershell works fine though.\n    vim.defer_fn(function()\n      send(nil, string.char(13))\n      if type(data) ~= \"string\" then\n        send(nil, string.char(13))\n      end\n    end, 150)\n  end\nend\n\ncore.send_file = function(ft)\n  core.send(ft, vim.api.nvim_buf_get_lines(0, 0, -1, false))\nend\n\n--- Sends the line under the cursor to the repl\n-- Builds upon @{core.send}, extracting\n-- the data beforehand.\ncore.send_line = function()\n  local linenr = vim.api.nvim_win_get_cursor(0)[1] - 1\n  local cur_line = vim.api.nvim_buf_get_lines(0, linenr, linenr + 1, 0)[1]\n  local width = vim.fn.strwidth(cur_line)\n\n  if width == 0 then return end\n\n  marks.set {\n    from_line = linenr,\n    from_col = 0,\n    to_line = linenr,\n    to_col = width - 1\n  }\n\n  core.send(nil, cur_line)\nend\n\n--- Sends the buffer from the beginning until reching the line where the cursor is (inclusive)\n-- Builds upon @{core.send}, extracting\n-- the data beforehand.\ncore.send_until_cursor = function()\n  local linenr = vim.api.nvim_win_get_cursor(0)[1] - 1\n  local text_until_line = vim.api.nvim_buf_get_lines(0, 0, linenr + 1, 0)\n  local last_line = vim.api.nvim_buf_get_lines(0, linenr, linenr + 1, 0)[1]\n  local last_line_width = vim.fn.strwidth(last_line)\n\n  marks.set {\n    from_line = 0,\n    from_col = 0,\n    to_line = linenr,\n    to_col = last_line_width - 1\n  }\n\n  core.send(nil, text_until_line)\nend\n\n--- Marks visual selection and returns data for usage\n-- @treturn table Marked lines\ncore.mark_visual = function()\n  -- HACK Break out of visual mode\n  vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Esc>', false, true, true), 'nx', false)\n  local b_line, b_col\n  local e_line, e_col\n\n  local mode = vim.fn.visualmode()\n\n  b_line, b_col = unpack(vim.fn.getpos(\"'<\"), 2, 3)\n  e_line, e_col = unpack(vim.fn.getpos(\"'>\"), 2, 3)\n\n  if e_line < b_line or (e_line == b_line and e_col < b_col) then\n    e_line, b_line = b_line, e_line\n    e_col, b_col = b_col, e_col\n  end\n\n  local lines = vim.api.nvim_buf_get_lines(0, b_line - 1, e_line, 0)\n\n  if #lines == 0 then return end\n\n  if mode == \"\\22\" then\n    local b_offset = math.max(1, b_col) - 1\n    for ix, line in ipairs(lines) do\n      -- On a block, remove all presiding chars unless b_col is 0/negative\n      lines[ix] = vim.fn.strcharpart(line, b_offset, math.min(e_col, vim.fn.strwidth(line)))\n    end\n  elseif mode == \"v\" then\n    local last = #lines\n    local line_size = vim.fn.strwidth(lines[last])\n    local max_width = math.min(e_col, line_size)\n    if (max_width < line_size) then\n      -- If the selected width is smaller then total line, trim the excess\n      lines[last] = vim.fn.strcharpart(lines[last], 0, max_width)\n    end\n\n    if b_col > 1 then\n      -- on a normal visual selection, if the start column is not 1, trim the beginning part\n      lines[1] = vim.fn.strcharpart(lines[1], b_col - 1)\n    end\n  end\n\n  marks.set {\n    from_line = b_line - 1,\n    from_col = math.max(b_col - 1, 0),\n    to_line = e_line - 1,\n    to_col = math.min(e_col, vim.fn.strwidth(lines[#lines])) - 1 -- TODO Check whether this is actually true\n  }\n\n  if config.ignore_blank_lines then\n    local b_lines = {}\n    for _, line in ipairs(lines) do\n      if line:gsub(\"^%s*(.-)%s*$\", \"%1\") ~= '' then\n        table.insert(b_lines, line)\n      end\n    end\n    return b_lines\n  else\n    return lines\n  end\nend\n\n--- Marks the supplied motion and returns the data for usage\n-- @tparam string mtype motion type\n-- @treturn table Marked lines\ncore.mark_motion = function(mtype)\n  local b_line, b_col\n  local e_line, e_col\n\n  b_line, b_col = unpack(vim.fn.getpos(\"'[\"), 2, 3)\n  e_line, e_col = unpack(vim.fn.getpos(\"']\"), 2, 3)\n\n  local lines = vim.api.nvim_buf_get_lines(0, b_line - 1, e_line, 0)\n  if #lines == 0 then return end\n\n  if mtype == 'line' then\n    b_col, e_col = 0, vim.fn.strwidth(lines[#lines])\n  end\n\n  if e_col > 1 then\n    lines[#lines] = vim.fn.strpart(lines[#lines], 0, e_col)\n  end\n  if b_col > 1 then\n    lines[1] = vim.fn.strpart(lines[1], b_col - 1)\n  end\n\n  marks.set {\n    from_line = b_line - 1,\n    from_col = math.max(b_col - 1, 0),\n    to_line = e_line - 1,\n    to_col = e_col - 1\n  }\n\n  marks.winrestview()\n  return lines\nend\n\n--- Sends a chunk of text from a motion to the repl\n-- It is a simple wrapper over @{core.mark_motion}\n-- in which the data is extracted by that function and sent to the repl.\n-- @{core.send} will handle the null cases.\n-- Additionally, it restores the cursor position as a side-effect.\n-- @param mtype motion type\ncore.send_motion = function(mtype)\n  core.send(nil, core.mark_motion(mtype))\nend\n\n--- Sends a chunk of text from a visual selection to the repl\n-- this is a simple wrapper over @{core.mark_visual} where\n-- the data is forwarded to the repl through @{core.send},\n-- which will handle the null cases.\ncore.visual_send = function()\n  core.send(nil, core.mark_visual())\nend\n\n--- Sends the paragraph to the REPL that the cursor is on\ncore.send_paragraph = function()\n  vim.cmd('normal! vip')\n  vim.defer_fn(function()\n    core.visual_send()\n  end, 100)\nend\n\n\n--- Re-sends latest chunk of text.\n-- Sends text contained within a block delimited by\n-- the last sent chunk. Uses @{marks.get} to retrieve\n-- the boundaries.\ncore.send_mark = function()\n  local pos = marks.get()\n\n  if pos == nil then return end\n\n  local lines = vim.api.nvim_buf_get_lines(0, pos.from_line, pos.to_line + 1, 0)\n\n  if #lines == 1 then\n    if pos.from_col >= 1 or pos.to_col < vim.fn.strwidth(lines[1]) - 1 then\n      lines[1] = vim.fn.strpart(lines[1], pos.from_col, pos.to_col - pos.from_col + 1)\n    end\n  else\n    if pos.from_col >= 1 then\n      lines[1] = vim.fn.strpart(lines[1], pos.from_col)\n    end\n    if pos.to_col < vim.fn.strwidth(lines[#lines]) - 1 then\n      lines[#lines] = vim.fn.strpart(lines[#lines], 0, pos.to_col + 1)\n    end\n  end\n\n  core.send(nil, lines)\nend\n\n--- Checks if line starts with a divider.\n-- Helper function for core.send_code_block.\nlocal line_starts_with_block_divider = function(line, block_dividers)\n  for _, block_divider in pairs(block_dividers) do\n    local length_block_divider = string.len(block_divider)\n    if string.sub(line, 1, length_block_divider) == block_divider then return true end\n  end\nend\n\n--- Sends lines between two block dividers.\n-- Block dividers can be defined as table in the\n-- repl_definition under key block_dividers.\n-- The buffer is scanned from cursor till first line\n-- starting with a block_divider or the start of buffer.\n-- The buffer is scanned till end of buffer for next line\n-- starting with a block divider or end of buffer.\n-- If no block_divider is defined an error is returned.\n-- If move is true, the cursor is moved to the next block_divider\n-- for jumping through the code. If move is false, the cursor is\n-- not moved.\ncore.send_code_block = function(move)\n  local block_dividers = config.repl_definition[vim.bo[0].filetype].block_dividers\n  if block_dividers == nil then\n    error(\"No block_dividers defined for this repl in repl_definition!\")\n  end\n  local linenr = vim.api.nvim_win_get_cursor(0)[1] - 1\n  local buffer_text = vim.api.nvim_buf_get_lines(0, 0, -1, false)\n  local mark_start = linenr\n  while mark_start ~= 0 do\n    local line_text = buffer_text[mark_start + 1]\n    if line_starts_with_block_divider(line_text, block_dividers) then break end\n    mark_start = mark_start - 1\n  end\n  local buffer_length = vim.api.nvim_buf_line_count(0)\n  local mark_end = linenr + 1\n  while mark_end < buffer_length do\n    local line_text = buffer_text[mark_end + 1]\n    if line_starts_with_block_divider(line_text, block_dividers) then break end\n    mark_end = mark_end + 1\n  end\n  mark_end = mark_end - 1\n  local col_end = string.len(buffer_text[mark_end + 1]) - 1\n  marks.set {\n    from_line = mark_start,\n    from_col = 0,\n    to_line = mark_end,\n    to_col = col_end,\n  }\n  core.send_mark()\n  if move then vim.api.nvim_win_set_cursor(0, { math.min(mark_end + 2, buffer_length), 0 }) end\nend\n\n--- Attaches a buffer to a repl regardless of it's filetype\n-- If the repl doesn't exist it will be created\ncore.attach = function(ft, target)\n  local meta = ll.get(ft)\n\n  if not ll.repl_exists(meta) then\n    meta = core.repl_for(ft)\n  end\n\n  vim.b[target].repl = meta\nend\n\n--- Provide filtered list of supported fts\n-- Auxiliary function to be used by commands to show the user which fts they have\n-- available to start repls with\n-- @param partial input string\n-- @return table with supported filetypes matching input string\nlocal complete_fts = function(partial)\n  local starts_with_partial = function(key) return key:sub(1, #partial) == partial end\n  local custom_fts = vim.tbl_filter(starts_with_partial, vim.tbl_keys(config.repl_definition))\n  vim.list_extend(custom_fts, vim.tbl_filter(\n    function(i) return (not vim.tbl_contains(custom_fts, i)) and starts_with_partial(i) end,\n    vim.tbl_keys(require(\"iron.fts\")))\n  )\n\n  return custom_fts\nend\n\nlocal get_ft = function(arg)\n  if arg and arg ~= \"\" then\n    return arg\n  end\n  return ll.get_buffer_ft(0)\nend\n\n--- List of commands created by iron.nvim\n-- They'll only be set up after calling the @{core.setup} function\n-- which makes it possible to delay initialization and make startup faster.\n-- @local\n-- @table commands\n-- @field IronRepl command for @{core.repl_for}\nlocal commands = {\n  { \"IronAttach\", function(opts)\n    core.attach(get_ft(opts.fargs[1]), vim.api.nvim_get_current_buf())\n  end, { nargs = \"?\", complete = complete_fts } },\n  { \"IronRepl\", function(opts)\n    core.repl_for(get_ft(opts.fargs[1]))\n  end, { nargs = \"?\", complete = complete_fts } },\n  { \"IronHide\", function(opts)\n    core.hide_repl(get_ft(opts.fargs[1]))\n  end, { nargs = \"?\", complete = complete_fts } },\n  { \"IronSend\", function(opts)\n    local ft\n    if opts.bang then\n      ft = opts.fargs[1]\n      opts.fargs[1] = \"\"\n    else\n      ft = ll.get_buffer_ft(0)\n    end\n    if ft == nil then return end\n    local data = table.concat(opts.fargs, \" \")\n\n    core.send(ft, data)\n  end, {\n    bang = true,\n    nargs = \"+\",\n    complete = function(arg_lead, cmd_line)\n      local cmd = vim.split(cmd_line, \" \")\n      if #cmd <= 2 and string.find(cmd[1], \"!\") then\n        return complete_fts(arg_lead)\n      end\n    end\n  } },\n  { \"IronFocus\", function(opts)\n    local ft = get_ft(opts.fargs[1])\n    if ft == nil then return end\n\n    core.focus_on(ft)\n  end, { nargs = \"?\", complete = complete_fts } },\n  { \"IronWatch\", function(opts)\n    local handler\n\n    if opts.fargs[1] == \"mark\" then\n      handler = core.send_mark\n    elseif opts.fargs[1] == \"file\" then\n      -- Wrap send_file so we ignore autocmd argument\n      handler = function() core.send_file() end\n    else\n      error(\"Not a valid handler type\")\n    end\n\n    core.watch(handler)\n  end, {\n    nargs = 1,\n    complete = function(arg_lead, _)\n      local starts_with_partial = function(key) return key:sub(1, #arg_lead) == arg_lead end\n      return vim.tbl_filter(starts_with_partial, {\n        \"mark\",\n        \"file\"\n      })\n    end\n  } },\n  { \"IronReplHere\", function(opts)\n    local ft = get_ft(opts.fargs[1])\n    if ft == nil then return end\n\n    core.repl_here(ft)\n  end, { nargs = \"?\", complete = complete_fts } },\n  { \"IronRestart\", function(_) core.repl_restart() end, { nargs = 0 } }\n}\n\n--- Wrapper for calling functions through motion.\n-- This should take care of the vim side of calling opfuncs.\n-- @param motion_fn_name name of the function in @{core} to be mapped\ncore.run_motion = function(motion_fn_name)\n  marks.winsaveview()\n  vim.o.operatorfunc = \"v:lua.require'iron.core'.\" .. motion_fn_name\n  vim.api.nvim_feedkeys(\"g@\", \"ni\", false)\nend\n\ncore.unwatch = function(bufnr)\n  local fname = vim.api.nvim_buf_get_name(bufnr)\n  if autocmds[fname] ~= nil then\n    vim.api.nvim_del_autocmd(autocmds[fname])\n    autocmds[fname] = nil\n  end\nend\n\ncore.watch = function(handler, bufnr)\n  bufnr = bufnr or vim.api.nvim_get_current_buf()\n  core.unwatch(bufnr)\n  local fname = vim.api.nvim_buf_get_name(bufnr)\n  autocmds[fname] = vim.api.nvim_create_autocmd(\"BufWritePost\", {\n    group = \"iron\",\n    pattern = fname,\n    callback = handler,\n    desc = \"Watch writes to buffer to send data to repl\"\n  })\nend\n\n--- List of keymaps\n-- if @{config}.should\\_map\\_plug is set to true,\n-- then they will also be mapped to `<plug>` keymaps.\n-- @table named_maps\n-- @field send_motion mapping to send a motion/chunk to the repl\n\n-- @field send_mark Sends chunk within marked boundaries\n-- @field send_line sends current line to repl\n-- @field send_until_cursor sends the buffer from the start until the line where the cursor is (inclusive) to the repl\n-- @field visual_send sends visual selection to repl\n-- @field clear_hl clears highlighted chunk\n-- @field cr sends a <CR> to the repl\n-- @field interrupt sends a <C-c> to the repl\n-- @field exit closes the repl\n-- @field clear clears the text buffer of the repl\nlocal named_maps = {\n  -- basic interaction with the repl\n  send_motion = {\n    { 'n' },\n    function() require(\"iron.core\").run_motion(\"send_motion\") end\n  },\n  send_mark = { { 'n' }, core.send_mark },\n  send_line = { { 'n' }, core.send_line },\n  send_until_cursor = { { 'n' }, core.send_until_cursor },\n  send_file = { { 'n' }, core.send_file },\n  visual_send = { { 'v' }, core.visual_send },\n  send_paragraph = { { 'n' }, core.send_paragraph },\n  send_code_block = { { 'n' }, function() core.send_code_block(false) end },\n  send_code_block_and_move = {\n    { 'n' }, function() core.send_code_block(true) end\n  },\n\n  -- REPL\n  restart_repl = { { 'n' }, function() vim.cmd(\"IronRestart\") end },\n  toggle_repl = { { 'n' }, function() vim.cmd(\"IronRepl\") end },\n\n  -- Marks\n  mark_motion = { { 'n' }, function() require(\"iron.core\").run_motion(\"mark_motion\") end },\n  mark_visual = { { 'v' }, core.mark_visual },\n  remove_mark = { { 'n' }, marks.drop_last },\n\n  -- Force clear highlight\n  clear_hl = { { 'v' }, marks.clear_hl },\n\n  -- Sending special characters to the repl\n  cr = { { 'n' }, function() core.send(nil, string.char(13)) end },\n  interrupt = { { 'n' }, function() core.send(nil, string.char(03)) end },\n  exit = { { 'n' }, core.close_repl },\n  clear = { { 'n' }, function() core.send(nil, string.char(12)) end },\n}\n\nlocal tmp_migration = {\n  repeat_cmd = \"send_mark\"\n}\n\nlocal snake_to_kebab = function(name)\n  return name:gsub(\"_\", \"-\")\nend\n\n--- Sets up the configuration for iron to run.\n-- Also, defines commands and keybindings for iron to run.\n-- @param opts table of the configuration to be applied\n-- @tparam table opts.config set of config values to override default on @{config}\n-- @tparam table opts.keymaps set of keymaps to apply, based on @{named_maps}\ncore.setup = function(opts)\n  config.namespace = vim.api.nvim_create_namespace(\"iron\")\n  vim.api.nvim_create_augroup(\"iron\", {})\n\n  if opts.config then\n    if type(opts.config.repl_open_cmd) ~= \"table\" then\n      ll.tmp.repl_open_cmd = opts.config.repl_open_cmd\n\n    else\n      for idx, cmd in ipairs(opts.config.repl_open_cmd) do\n        if idx == 1 then\n          ll.tmp.repl_open_cmd = cmd\n        end\n        named_maps[\"toggle_repl_with_cmd_\" .. idx] = {\n          { 'n' },\n          function()\n            ll.tmp.repl_open_cmd = cmd\n            vim.cmd('IronRepl')\n          end\n        }\n      end\n    end\n\n    if opts.config.dap_integration then\n      dap.enable_integration()\n    end\n\n    if ll.tmp.repl_open_cmd == nil then\n      local msg = \"A default repl_open_cmd was not set. \"\n      msg = msg .. \"Please set a default by adding '_DEFAULT' \"\n      msg = msg .. \"to the end of one of your repl_open_cmd names.\"\n      error(msg)\n    end\n\n    for k, v in pairs(opts.config) do\n      config[k] = v\n    end\n\n  else\n    ll.tmp.repl_open_cmd = config.repl_open_cmd\n  end\n\n\n  if config.highlight_last ~= false then\n    local hl_cfg = opts.highlight or {\n      bold = true\n    }\n\n\n    vim.api.nvim_set_hl(0, config.highlight_last, hl_cfg)\n  end\n\n  for _, command in ipairs(commands) do\n    vim.api.nvim_create_user_command(unpack(command))\n  end\n\n  if config.should_map_plug then\n    vim.deprecate(\"config.should_map_plug\", \"core.setup{keymaps = {...}}\", \"3.1\", \"iron.nvim\")\n    for key, keymap in pairs(named_maps) do\n      local mapping = vim.deepcopy(keymap)\n      table.insert(mapping, 2, \"<plug>(iron-\" .. snake_to_kebab(key) .. \")\")\n      table.insert(mapping, { silent = true })\n      vim.keymap.set(unpack(mapping))\n    end\n  end\n\n  if opts.keymaps ~= nil then\n    for key, lhs in pairs(opts.keymaps) do\n      if tmp_migration[key] ~= nil then\n        log.deprecate(\n          \"core.setup{keymaps.\" .. key .. \"}\",\n          \"core.setup{keymaps.\" .. tmp_migration[key] .. \"}\",\n          \"3.1\",\n          \"iron.nvim\"\n        )\n        key = tmp_migration[key]\n      end\n\n      if named_maps[key] == nil then\n        error(\"Key `\" .. key .. \"` doesn't exist, therefore there's nothing to be applied\")\n      else\n        local mapping = vim.deepcopy(named_maps[key])\n        table.insert(mapping, 2, lhs)\n        table.insert(mapping, { silent = true, desc = 'iron_repl_' .. key })\n\n        vim.keymap.set(unpack(mapping))\n      end\n    end\n  end\nend\n\nreturn core\n"
  },
  {
    "path": "lua/iron/dap.lua",
    "content": "local M = {}\n\nlocal is_dap_integration_enabled = false\n\n--- Sets up a hook to keep track of the DAP session state.\nfunction M.enable_integration()\n  is_dap_integration_enabled = true\nend\n\n--- Returns true if dap_integration is enabled and a dap session is running.\n--- This function will always return false if dap_integration is not enabled.\n--- @return boolean\nfunction M.is_dap_session_running()\n  local has_dap, dap = pcall(require, 'dap')\n  return has_dap and is_dap_integration_enabled and dap.session() ~= nil\nend\n\n--- Send the lines to the dap-repl\n--- @param lines string|string[]\nfunction M.send_to_dap(lines)\n  local text\n  if type(lines) == 'table' then\n    text = table.concat(lines, \"\\n\"):gsub('\\r', '')\n  else\n    text = lines\n  end\n  require('dap').repl.execute(text)\n  require('dap').repl.open()\nend\n\nreturn M\n"
  },
  {
    "path": "lua/iron/debug_level.lua",
    "content": "--- Sets the level of debug\n--@module debug_level\nlocal debug_level = {}\n\ndebug_level.fatal = 1\ndebug_level.err   = 2\ndebug_level.warn  = 3\ndebug_level.info  = 4\n\nreturn debug_level\n"
  },
  {
    "path": "lua/iron/fts/clojure.lua",
    "content": "local clojure = {}\n\nclojure.boot = {\n  command = {\"boot\", \"repl\"},\n}\n\nclojure.lein = {\n  command = {\"lein\", \"repl\"},\n}\n\nclojure.clj = {\n  command = {\"clj\"},\n}\n\nreturn clojure\n"
  },
  {
    "path": "lua/iron/fts/common.lua",
    "content": "local is_windows = require(\"iron.util.os\").is_windows\nlocal extend = require(\"iron.util.tables\").extend\nlocal open_code = \"\\27[200~\"\nlocal close_code = \"\\27[201~\"\nlocal cr = \"\\13\"\n\nlocal common = {}\n\n\n---@param table table table of strings\n---@param substring string\n--- Checks in any sting in the table contains the substring\nlocal contains = function(table, substring)\n  for _, v in ipairs(table) do\n    if string.find(v, substring) then\n      return true\n    end\n  end\n  return false\nend\n\n\n---@param lines table\n-- Removes empty lines. On unix this includes lines only with whitespaces.\nlocal function remove_empty_lines(lines)\n  local newlines = {}\n\n  for _, line in pairs(lines) do\n    if string.len(line:gsub(\"[ \\t]\", \"\")) > 0 then\n      table.insert(newlines, line)\n    end\n  end\n\n  return newlines\nend\n\n\n---@param s string\n--- A helper function using in bracked_paste_python.\n-- Checks in a string starts with any of the exceptions.\nlocal function python_close_indent_exceptions(s)\n  local exceptions = { \"elif\", \"else\", \"except\", \"finally\", \"#\" }\n  for _, exception in ipairs(exceptions) do\n    local pattern0 = \"^\" .. exception .. \"[%s:]\"\n    local pattern1 = \"^\" .. exception .. \"$\"\n    if string.match(s, pattern0) or string.match(s, pattern1) then\n      return true\n    end\n  end\n  return false\nend\n\n\ncommon.format = function(repldef, lines)\n  assert(type(lines) == \"table\", \"Supplied lines is not a table\")\n\n  local new\n\n  -- passing the command is for python. this will not affect bracketed_paste.\n  if repldef.format then\n    return repldef.format(lines, { command = repldef.command })\n  elseif #lines == 1 then\n    new = lines\n  else\n    new = extend(repldef.open, lines, repldef.close)\n  end\n\n  if #new > 0 then\n    if not is_windows() then\n      new[#new] = new[#new] .. cr\n    end\n  end\n\n  return new\nend\n\n\ncommon.bracketed_paste = function(lines)\n  if #lines == 1 then\n    return { lines[1] .. cr }\n  else\n    local new = { open_code .. lines[1] }\n    for line = 2, #lines do\n      table.insert(new, lines[line])\n    end\n\n    table.insert(new, close_code .. cr)\n\n    return new\n  end\nend\n\n\n--- @param lines table  \"each item of the table is a new line to send to the repl\"\n--- @return table  \"returns the table of lines to be sent the the repl with\n-- the return carriage added\"\ncommon.bracketed_paste_python = function(lines, extras)\n  local result = {}\n\n  local cmd = extras[\"command\"]\n  local pseudo_meta = { current_buffer = vim.api.nvim_get_current_buf()}\n  if type(cmd) == \"function\" then\n    cmd = cmd(pseudo_meta)\n  end\n\n  local windows = is_windows()\n  local python = false\n  local ipython = false\n  local ptpython = false\n\n  if contains(cmd, \"ipython\") then\n    ipython = true\n  elseif contains(cmd, \"ptpython\") then\n    ptpython = true\n  else\n    python = true\n  end\n\n  lines = remove_empty_lines(lines)\n\n  local indent_open = false\n  for i, line in ipairs(lines) do\n    if string.match(line, \"^%s\") ~= nil then\n      indent_open = true\n    end\n\n    table.insert(result, line)\n\n    if windows and python or not windows then\n      if i < #lines and indent_open and string.match(lines[i + 1], \"^%s\") == nil then\n        if not python_close_indent_exceptions(lines[i + 1]) then\n          indent_open = false\n          table.insert(result, cr)\n        end\n      end\n    end\n  end\n\n  local newline = windows and \"\\r\\n\" or cr\n  if #result == 0 then  -- handle sending blank lines\n    table.insert(result, cr)\n  elseif #result > 0 and result[#result]:sub(1, 1) == \" \" then\n    -- Since the last line of code is indented, the Python REPL\n    -- requires and extra newline in order to execute the code\n    table.insert(result, newline)\n  else\n    if not is_windows() then\n      table.insert(result, \"\")\n    end\n  end\n\n  if ptpython then\n    table.insert(result, 1, open_code)\n    table.insert(result, close_code)\n    table.insert(result, \"\\n\")\n  end\n\n  return result\nend\n\n\nreturn common\n"
  },
  {
    "path": "lua/iron/fts/cpp.lua",
    "content": "\nlocal cpp = {}\n\nlocal function magic(str)\n    -- remove every space at beginning of a line\n    str = str:gsub('^%s+', '')\n    -- remove all comments\n    str = str:gsub('//(.*)', '')\n    -- remove every space at end of a line\n    str = str:gsub('%s+$', '')\n    -- remove line break and extra spaces eventually\n    str = str:gsub([[\\$]], '')\n    str = str:gsub('%s+$', '')\n    return str\nend\n\nlocal function lastmagic(str)\n    -- check what character is the last of the line\n    if str:len() == 0 then return false end\n    local lastchar = str:sub(-1, -1)\n    return lastchar == ';' or lastchar == '{' or lastchar == '}'\nend\n\nlocal function format(lines)\n    if #lines == 1 then\n        return {magic(lines[1]) .. '\\13'}\n    else\n        local new = {}\n        local aus = ''\n        for line = 1, #lines do\n            -- concatenate lines if they do not end with a lastmagic character.\n            local l = magic(lines[line])\n            aus = aus .. l\n            if lastmagic(l) then\n                table.insert(new, aus)\n                aus = ''\n            end\n        end\n        return table.insert(new, '')\n    end\nend\n\ncpp.root = {command = {'root', '-l'}, format = format}\n\nreturn cpp\n"
  },
  {
    "path": "lua/iron/fts/csh.lua",
    "content": "local csh = {}\n\ncsh.csh = {\n  command = {\"csh\"},\n}\n\ncsh.tcsh = {\n  command = {\"tch\"},\n}\n\nreturn csh\n"
  },
  {
    "path": "lua/iron/fts/elixir.lua",
    "content": "local elixir = {}\n\nelixir.iex = {\n  command = {\"iex\"},\n}\n\nreturn elixir\n"
  },
  {
    "path": "lua/iron/fts/elm.lua",
    "content": "local elm = {}\n\nelm.elm = {\n  command = {\"elm\", \"repl\"},\n}\n\nelm.elm_legacy = {\n  command = {\"elm-repl\"},\n}\n\nreturn elm\n"
  },
  {
    "path": "lua/iron/fts/erlang.lua",
    "content": "local erlang = {}\n\nerlang.erl = {\n  command = {\"erl\"},\n}\n\nreturn erlang\n"
  },
  {
    "path": "lua/iron/fts/fennel.lua",
    "content": "local fennel = {}\n\nfennel.fennel = {\n  command = {\"fennel\"},\n}\n\nreturn fennel\n"
  },
  {
    "path": "lua/iron/fts/fish.lua",
    "content": "local fish = {}\n\nfish.fish = {\n  command = {\"fish\"},\n}\n\nreturn fish\n"
  },
  {
    "path": "lua/iron/fts/forth.lua",
    "content": "local forth = {}\n\nforth.gforth = {\n  command = {\"gforth\"}\n}\n\nreturn forth\n"
  },
  {
    "path": "lua/iron/fts/haskell.lua",
    "content": "local haskell = {}\n\nhaskell.stack_intero = {\n  command = {\"stack\", \"ghci\", \"--with-ghc\", \"intero\"},\n}\n\nhaskell.stack = {\n  command = {\"stack\", \"ghci\"},\n}\n\nhaskell.cabal = {\n  command = {\"cabal\", \"repl\"},\n}\n\nhaskell.ghci = {\n  command = {\"ghci\"},\n}\n\nreturn haskell\n"
  },
  {
    "path": "lua/iron/fts/hy.lua",
    "content": "local hy = {}\n\nhy.hy = {\n  command = {\"hy\"}\n}\n\nreturn hy\n"
  },
  {
    "path": "lua/iron/fts/init.lua",
    "content": "-- luacheck: globals unpack\n\nlocal fts = {\n  clojure = require(\"iron.fts.clojure\"),\n  cpp = require(\"iron.fts.cpp\"),\n  csh = require(\"iron.fts.csh\"),\n  elixir = require(\"iron.fts.elixir\"),\n  elm = require(\"iron.fts.elm\"),\n  erlang = require(\"iron.fts.erlang\"),\n  fennel = require(\"iron.fts.fennel\"),\n  forth = require(\"iron.fts.forth\"),\n  haskell = require(\"iron.fts.haskell\"),\n  hy = require(\"iron.fts.hy\"),\n  janet = require(\"iron.fts.janet\"),\n  javascript = require(\"iron.fts.javascript\"),\n  julia = require(\"iron.fts.julia\"),\n  lisp = require(\"iron.fts.lisp\"),\n  lua = require(\"iron.fts.lua\"),\n  mma = require(\"iron.fts.mma\"),\n  ocaml = require(\"iron.fts.ocaml\"),\n  php = require(\"iron.fts.php\"),\n  prolog = require(\"iron.fts.prolog\"),\n  ps1 = require(\"iron.fts.ps1\"),\n  pure = require(\"iron.fts.pure\"),\n  python = require(\"iron.fts.python\"),\n  r = require(\"iron.fts.r\"),\n  racket = require(\"iron.fts.racket\"),\n  ruby = require(\"iron.fts.ruby\"),\n  sbt_scala = require(\"iron.fts.sbt\"),\n  scala = require(\"iron.fts.scala\"),\n  scheme = require(\"iron.fts.scheme\"),\n  sh = require(\"iron.fts.sh\"),\n  stata = require(\"iron.fts.stata\"),\n  tcl = require(\"iron.fts.tcl\"),\n  typescript = require(\"iron.fts.typescript\"),\n  zsh = require(\"iron.fts.zsh\"),\n  fish = require(\"iron.fts.fish\")\n}\n\nreturn fts\n"
  },
  {
    "path": "lua/iron/fts/janet.lua",
    "content": "local janet = {}\n\njanet.janet = {\n  command = {\"janet\"},\n}\n\nreturn janet\n"
  },
  {
    "path": "lua/iron/fts/javascript.lua",
    "content": "local javascript = {}\n\njavascript.node = {\n  command = {\"node\"},\n  open = \".editor\\n\",\n  close = \"\\04\",\n}\n\nreturn javascript\n"
  },
  {
    "path": "lua/iron/fts/julia.lua",
    "content": "local julia = {}\n\njulia.julia = {\n  command = {\"julia\"},\n}\n\nreturn julia\n"
  },
  {
    "path": "lua/iron/fts/lisp.lua",
    "content": "local lisp = {}\n\nlisp.sbcl = {\n  command = {\"sbcl\"},\n}\n\nlisp.clisp = {\n  command = {\"clisp\"},\n}\n\nreturn lisp\n"
  },
  {
    "path": "lua/iron/fts/lua.lua",
    "content": "local lua = {}\n\nlua.lua = {\n  command = {\"lua\"},\n}\n\nreturn lua\n"
  },
  {
    "path": "lua/iron/fts/markdown.lua",
    "content": "local markdown = {}\n\nmarkdown.aichat = {\n  command = \"aichat\",\n  format = require(\"iron.fts.common\").bracketed_paste,\n}\n\nreturn markdown\n"
  },
  {
    "path": "lua/iron/fts/mma.lua",
    "content": "local mma = {}\n\nmma.math = {\n  command = { \"math\" },\n}\n\nreturn mma\n"
  },
  {
    "path": "lua/iron/fts/ocaml.lua",
    "content": "local ocaml = {}\n\nocaml.utop = {\n  command = {\"utop\"},\n}\n\nocaml.ocamltop = {\n  command = {\"ocamltop\"},\n}\n\nreturn ocaml\n"
  },
  {
    "path": "lua/iron/fts/php.lua",
    "content": "local php = {}\n\nphp.psysh = {\n  command = {\"psysh\"},\n}\n\nphp.php = {\n  command = {\"php\", \"-a\"},\n}\n\nreturn php\n"
  },
  {
    "path": "lua/iron/fts/prolog.lua",
    "content": "local prolog = {}\n\nprolog.gprolog = {\n  command = {\"gprolog\"},\n}\n\nprolog.swipl = {\n  command = {\"swipl\"},\n}\n\nreturn prolog\n"
  },
  {
    "path": "lua/iron/fts/ps1.lua",
    "content": "local ps1 = {}\n\nps1.ps1 = {\n  command = {\"powershell\", \"-noexit\", \"-executionpolicy\", \"bypass\"},\n}\n\nreturn ps1\n"
  },
  {
    "path": "lua/iron/fts/pure.lua",
    "content": "local pure = {}\n\npure.pure = {\n  command = {\"pure\"},\n  open = \":paste\\n\",\n  close = \"\\04\",\n}\n\nreturn pure\n"
  },
  {
    "path": "lua/iron/fts/python.lua",
    "content": "-- luacheck: globals vim\nlocal bracketed_paste_python = require(\"iron.fts.common\").bracketed_paste_python\nlocal python = {}\n\nlocal executable = function(exe)\n  return vim.api.nvim_call_function('executable', {exe}) == 1\nend\n\nlocal pyversion  = executable('python3') and 'python3' or 'python'\n\nlocal def = function(cmd)\n\treturn {\n\t\tcommand = cmd,\n\t\tformat = bracketed_paste_python\n\t}\nend\n\npython.ptipython = def({\"ptipython\"})\npython.ipython = def({\"ipython\", \"--no-autoindent\"})\npython.ptpython = def({\"ptpython\"})\npython.python = def({pyversion})\n\nreturn python\n"
  },
  {
    "path": "lua/iron/fts/r.lua",
    "content": "local bracketed_paste = require(\"iron.fts.common\").bracketed_paste\nlocal r = {}\n\nr.R = {\n    command = { \"R\" },\n    format = bracketed_paste\n}\n\nr.radian = {\n    command = { \"radian\" },\n    format = bracketed_paste\n}\n\nreturn r\n"
  },
  {
    "path": "lua/iron/fts/racket.lua",
    "content": "local racket = {}\n\nracket.racket = {\n  command = {\"racket\"},\n}\n\nreturn racket\n"
  },
  {
    "path": "lua/iron/fts/ruby.lua",
    "content": "local ruby = {}\n\nruby.irb = {\n  command = {\"irb\"},\n}\n\nreturn ruby\n"
  },
  {
    "path": "lua/iron/fts/sbt.lua",
    "content": "local sbt = {}\n\nsbt.sbt = {\n  command = {\"sbt\"},\n  open = \":paste\\n\",\n  close = \"\\04\",\n}\n\nreturn sbt\n"
  },
  {
    "path": "lua/iron/fts/scala.lua",
    "content": "local scala = {}\n\nlocal def = function(command)\n  return {\n    command = command,\n    open = \":paste\",\n    close = \"\\04\"\n  }\nend\n\nscala.sbt = def{\"sbt\"}\nscala.scala = def{\"scala\"}\n\nreturn scala\n"
  },
  {
    "path": "lua/iron/fts/scheme.lua",
    "content": "local scheme = {}\n\nscheme.guile = {\n  command = {\"guile\"},\n}\n\nscheme.csi = {\n  command = {\"csi\"},\n}\n\nreturn scheme\n"
  },
  {
    "path": "lua/iron/fts/sh.lua",
    "content": "local sh = {}\n\nsh.bash = {\n  command = {\"bash\"},\n}\n\nsh.sh = {\n  command = function(meta)\n    local bufnr = meta.current_bufnr\n    if vim.b[bufnr].is_posix == 1 then\n      return {\"sh\"}\n    elseif vim.b[bufnr].is_bash == 1 then\n      return {\"bash\"}\n    elseif vim.b[bufnr].is_kornshell == 1 then\n      return {\"ksh\"}\n    else\n      return {\"sh\"}\n    end\n  end,\n}\n\nreturn sh\n"
  },
  {
    "path": "lua/iron/fts/stata.lua",
    "content": "local stata = {}\n\nstata.stata = {\n\tcommand = { \"stata\", \"-q\" },\n}\n\nreturn stata\n"
  },
  {
    "path": "lua/iron/fts/tcl.lua",
    "content": "local tcl = {}\n\ntcl.tclsh = {\n  command = {\"tclsh\"},\n}\n\nreturn tcl\n"
  },
  {
    "path": "lua/iron/fts/typescript.lua",
    "content": "local typescript = {}\n\ntypescript.ts = {\n  command = {\"ts-node\"},\n  open = \".editor\\n\",\n  close = \"\\04\",\n}\n\nreturn typescript\n"
  },
  {
    "path": "lua/iron/fts/zsh.lua",
    "content": "local zsh = {}\n\nzsh.zsh = {\n  command = {\"zsh\"},\n}\n\nreturn zsh\n"
  },
  {
    "path": "lua/iron/init.lua",
    "content": "-- luacheck: globals unpack vim\n\nlocal iron = {\n  -- Will eventually be removed\n  config = require(\"iron.config\"),\n  -- Most likely shouldn't be exposed here\n  ll = require(\"iron.lowlevel\"),\n  core = require(\"iron.core\"),\n  setup = require(\"iron.core\").setup\n}\n\nreturn iron\n"
  },
  {
    "path": "lua/iron/log.lua",
    "content": "-- luacheck: globals vim\nlocal log = {}\n\nif vim.deprecate then\n  log.deprecate = vim.deprecate\nelse\n  log.deprecate = function(old, new, version, app)\n    local message = [[%s is deprecated, use %s instead. See :h deprecated\nThis function will be removed in %s version %s]]\n\n    error(string.format(message, old, new, app, version))\n  end\nend\n\nreturn log\n"
  },
  {
    "path": "lua/iron/lowlevel.lua",
    "content": "-- luacheck: globals vim\n-- TODO Remove config from this layer\nlocal config = require(\"iron.config\")\nlocal fts = require(\"iron.fts\")\nlocal providers = require(\"iron.providers\")\nlocal format = require(\"iron.fts.common\").format\nlocal view = require(\"iron.view\")\nlocal is_windows = require(\"iron.util.os\").is_windows\n\n--- Low level functions for iron\n-- This is needed to reduce the complexity of the user API functions.\n-- There are a few rules to the functions in this document:\n--    * They should not interact with each other\n--        * An exception for this is @{lowlevel.get_repl_def} during the transition to v3\n--    * They should do one small thing only\n--    * They should not care about setting/cleaning up state (i.e. moving back to another window)\n--    * They must be explicit in their documentation about the state changes they cause.\n-- @module lowlevel\n-- @alias ll\nlocal ll = {}\n\nll.store = {}\n\n-- Quick fix for changing repl_open_cmd\nll.tmp = {}\n\n-- TODO This should not be part of lowlevel\nll.get = function(ft)\n  if ft == nil or ft == \"\" then\n    error(\"Empty filetype\")\n  end\n  return config.scope.get(ll.store, ft)\nend\n\n-- TODO this should not be part of lowlevel\nll.set = function(ft, fn)\n  return config.scope.set(ll.store, ft, fn)\nend\n\nll.get_buffer_ft = function(bufnr)\n  local ft = vim.bo[bufnr].filetype\n  if ft == nil or ft == \"\" then\n    error(\"Empty filetype\")\n  elseif fts[ft] == nil and config.repl_definition[ft] == nil then\n    error(\"There's no REPL definition for current filetype \"..ft)\n  end\n  return ft\nend\n\n--- Creates the repl in the current window\n-- This function effectively creates the repl without caring\n-- about window management. It is expected that the client\n-- ensures the right window is created and active before calling this function.\n-- If @{\\\\config.close_window_on_exit} is set to true, it will plug a callback\n-- to the repl so the window will automatically close when the process finishes\n-- @param ft filetype of the current repl\n-- @param repl definition of the repl being created\n-- @param repl.command table with the command to be invoked.\n-- @param bufnr Buffer to be used\n-- @param current_bufnr Current buffer\n-- @param opts Options passed through to the terminal\n-- @warning changes current window's buffer to bufnr\n-- @return unsaved metadata about created repl\nll.create_repl_on_current_window = function(ft, repl, bufnr, current_bufnr, opts)\n  vim.api.nvim_win_set_buf(0, bufnr)\n  -- TODO Move this out of this function\n  -- Checking config should be done on an upper layer.\n  -- This layer should be simpler\n  opts = opts or {}\n  if config.close_window_on_exit then\n    opts.on_exit = function()\n      local bufwinid = vim.fn.bufwinid(bufnr)\n      while bufwinid ~= -1 do\n        vim.api.nvim_win_close(bufwinid, true)\n        bufwinid = vim.fn.bufwinid(bufnr)\n      end\n      if vim.api.nvim_buf_is_valid(bufnr) then\n        vim.api.nvim_buf_delete(bufnr, { force = true })\n      end\n    end\n  else\n    opts.on_exit = function() end\n  end\n\n  local cmd = repl.command\n  if type(repl.command) == 'function' then\n    local meta = {\n      current_bufnr = current_bufnr,\n    }\n    cmd = repl.command(meta)\n  end\n\n  if repl.env then\n    opts.env = repl.env\n  end\n\n  local job_id = vim.fn.termopen(cmd, opts)\n\n  return {\n    ft = ft,\n    bufnr = bufnr,\n    job = job_id,\n    repldef = repl\n  }\nend\n\n--- Wrapper function for getting repl definition from config\n-- This allows for an easier transition between old and new methods\n-- @tparam string ft filetype of the desired repl\n-- @return repl definition\nll.get_repl_def = function(ft)\n  -- TODO should not call providers directly, but from config\n  return config.repl_definition[ft] or providers.first_matching_binary(ft)\nend\n\n--- Creates a new window for placing a repl.\n-- Expected to be called before creating the repl.\n-- It knows nothing about the repl and only takes in account the\n-- configuration.\n-- @warning might change the current window\n-- @param bufnr buffer to be used\n-- @param repl_open_cmd command to be used to open the repl. if nil than will use config.repl_open_cmd\n-- @return window id of the newly created window\nll.new_window = function(bufnr, repl_open_cmd)\n  if repl_open_cmd == nil then\n    repl_open_cmd = ll.tmp.repl_open_cmd\n  end\n\n  if type(repl_open_cmd) == \"function\" then\n    local result = repl_open_cmd(bufnr)\n    if type(result) == \"table\" then\n      return view.openfloat(result, bufnr)\n    else\n      return result\n    end\n  else\n    vim.cmd(repl_open_cmd)\n    vim.api.nvim_set_current_buf(bufnr)\n    return vim.fn.bufwinid(bufnr)\n  end\nend\n\n--- Creates a new buffer to be used by the repl\n-- @return the buffer id\nll.new_buffer = function()\n  return vim.api.nvim_create_buf(config.buflisted, config.scratch_repl)\nend\n\n--- Wraps the condition checking of whether a repl exists\n-- created for convenience\n-- @tparam table meta metadata for repl. Can be nil.\n-- @treturn boolean whether the repl exists\nll.repl_exists = function(meta)\n  return meta ~= nil and vim.api.nvim_buf_is_loaded(meta.bufnr)\nend\n\n--- Sends data to an existing repl of given filetype\n-- The content supplied is ensured to be a table of lines,\n-- being coerced if supplied as a string.\n-- As a side-effect of pasting the contents to the repl,\n-- it changes the scroll position of that window.\n-- Does not affect currently active window and its cursor position.\n-- @tparam table meta metadata for repl. Should not be nil\n-- @tparam string ft name of the filetype\n-- @tparam string|table data A multiline string or a table containing lines to be sent to the repl\n-- @warning changes cursor position if window is visible\nll.send_to_repl = function(meta, data)\n  local dt = data\n  \n  if data == string.char(12) then\n    vim.fn.chansend(meta.job, {string.char(12)})\n    return\n  end\n\n  if type(data) == \"string\" then\n    dt = vim.split(data, '\\n')\n  end\n\n  dt = format(meta.repldef, dt)\n\n  local window = vim.fn.bufwinid(meta.bufnr)\n  if window ~= -1 then\n    vim.api.nvim_win_set_cursor(window, {vim.api.nvim_buf_line_count(meta.bufnr), 0})\n  end\n\n  --TODO check vim.api.nvim_chan_send\n  --TODO tool to get the progress of the chan send function\n  if is_windows() then\n    vim.fn.chansend(meta.job, table.concat(dt, \"\\r\"))\n  else\n    vim.fn.chansend(meta.job, dt)\n  end\n\n  if window ~= -1 then\n    vim.api.nvim_win_set_cursor(window, {vim.api.nvim_buf_line_count(meta.bufnr), 0})\n  end\nend\n\n\n--- Reshapes the repl window according to a preset config described in views\n-- @tparam table meta metadata for the repl\n-- @tparam string|number key either name or index in the table for the preset to be active\nll.set_window_shape = function(meta, key)\n  local window = vim.fn.bufwinid(meta.bufnr)\n  local preset = config.views[key]\n  if preset ~= nil then\n    if type(preset) == \"function\" then\n      preset = preset(meta.bufnr)\n    end\n    vim.api.nvim_win_set_config(window, preset)\n  end\nend\n\n--- Closes the window\n-- @tparam table meta metadata for the repl\nll.close_window = function(meta)\n  local window = vim.fn.bufwinid(meta.bufnr)\n  vim.api.nvim_win_close(window, true)\nend\n\n--- Tries to look up the corresponding filetype of a REPL\n-- If the corresponding buffer number is a repl,\n-- return its filetype otherwise return nil\n-- @tparam int bufnr number of the buffer being checked\n-- @treturn string filetype of the buffer's repl (or nil if it doesn't have a repl associated)\nll.get_repl_ft_for_bufnr = function(bufnr)\n  for _, values  in pairs(ll.store) do\n    for _, meta in pairs(values) do\n      if meta.bufnr == bufnr then\n        return meta.ft\n      end\n    end\n  end\nend\n\nreturn ll\n"
  },
  {
    "path": "lua/iron/marks.lua",
    "content": "-- luacheck: globals vim\nlocal config = require(\"iron.config\")\n\n--- Marks management for iron\n-- This is an intermediary layer between iron and neovim's\n-- extmarks. Used primarily to manage the text sent to the repl,\n-- but can also be used to set highlight and possibly virtualtext.\nlocal marks = {}\n\n--- Sets a mark for given options\n-- The mark is set for a preconfigured position id, which will be used by\n-- @{marks.get} for retrieval.\n-- @tparam table opts table with the directives\n-- @tparam number opts.from_line line where the mark starts\n-- @tparam number opts.to_line line where the mark ends. Can be ignored on single line marks\n-- @tparam number opts.from_col column where the mark starts\n-- @tparam number opts.to_col column where the mark ends\n-- @tparam string|false opts.hl Highlight group to be used or false if no highlight should be done.\nmarks.set = function(opts)\n  local extmark_config = {\n    id = config.mark.send,\n    -- to_line can be ignored if it's single line\n    end_line = opts.to_line or opts.from_line,\n    end_col = opts.to_col + 1\n  }\n\n  if opts.hl ~= nil then\n\n    -- Intentionally check here\n    -- so opts.false disables highlight\n    if opts.hl ~= false then\n      extmark_config.hl_group = opts.hl\n    end\n\n  elseif config.highlight_last then\n    extmark_config.hl_group = config.highlight_last\n  end\n\n  vim.api.nvim_buf_set_extmark(0, config.namespace, opts.from_line, opts.from_col, extmark_config)\nend\n\nmarks.drop_last = function()\n  vim.api.nvim_buf_del_extmark(0, config.namespace, config.mark.send)\nend\n\nmarks.clear_hl = function()\n  local payload = marks.get()\n  payload.hl = false\n  marks.set(payload)\nend\n\n--- Retrieves the mark with a position id.\nmarks.get = function()\n  local mark_pos = vim.api.nvim_buf_get_extmark_by_id(0, config.namespace, config.mark.send, {details = true})\n\n  if #mark_pos == 0 then\n    return nil\n  end\n\n  return {\n    from_line = mark_pos[1],\n    from_col = mark_pos[2],\n    to_line = mark_pos[3].end_row,\n    to_col = mark_pos[3].end_col - 1\n  }\n\nend\n\nmarks.winrestview = function()\n  local mark = vim.api.nvim_buf_get_extmark_by_id(0, config.namespace, config.mark.save_pos, {})\n\n  if #mark ~= 0 then\n    -- winrestview is 1-based\n    vim.fn.winrestview({lnum = mark[1] + 1, col = mark[2]})\n    vim.api.nvim_buf_del_extmark(0, config.namespace, config.mark.save_pos)\n  end\nend\n\nmarks.winsaveview = function()\n  local pos = vim.fn.winsaveview()\n  vim.api.nvim_buf_set_extmark(0, config.namespace, pos.lnum - 1, pos.col, {id = config.mark.save_pos})\nend\n\nreturn marks\n"
  },
  {
    "path": "lua/iron/providers.lua",
    "content": "-- luacheck: globals vim\nlocal fts = require(\"iron.fts\")\n\nlocal providers = {}\n\n--[[ TODO ensure there's a default provider\n\nThe user should configure default provider; if none provided, use `first_matching_binary`.\n\nThe user should also be allowed to set specific providers for specific languages\n--]]\n\nproviders.first_matching_binary = function(ft)\n  local repl_definitions = fts[ft]\n  if not repl_definitions then\n    error(\"No repl definition configured for \" .. ft)\n  end\n\n  local repl_def\n\n  for _, v in pairs(repl_definitions) do\n    if vim.fn.executable(v.command[1]) == 1 then\n      repl_def = v\n      break\n    end\n  end\n\n  if not repl_def then\n    error(\"Couldn't find a binary available for \" .. ft)\n  end\n  return repl_def\nend\n\nreturn providers\n"
  },
  {
    "path": "lua/iron/scope.lua",
    "content": "-- luacheck: globals vim\nlocal scope = {}\n\nlocal ensure_key = function(map, key)\n  map[key] = map[key] or {}\nend\n\nlocal default_map_set = function(map, base, key, value)\n  ensure_key(map, base)\n  map[base][key] = value\nend\n\nscope.tab_based = {\n  set = function(memory, ft, repl_data)\n    local tab = vim.fn.tabpagenr()\n    default_map_set(memory, ft, \"tab_\" .. tab, repl_data)\n    return repl_data\n  end,\n  get = function(memory, ft)\n    ensure_key(memory, ft)\n    local tab = vim.fn.tabpagenr()\n    return memory[ft][\"tab_\" .. tab]\n  end\n}\n\nscope.path_based = {\n  set = function(memory, ft, repl_data)\n    local pwd = vim.fn.getcwd()\n    default_map_set(memory, ft, \"pwd_\" .. pwd, repl_data)\n    return repl_data\n  end,\n  get = function(memory, ft)\n    ensure_key(memory, ft)\n    local pwd = vim.fn.getcwd()\n    return memory[ft][\"pwd_\" .. pwd]\n  end\n}\n\nscope.singleton = {\n  set = function(memory, ft, repl_data)\n    ensure_key(memory, ft)\n    default_map_set(memory, ft, \"singleton\", repl_data)\n    return repl_data\n  end,\n  get = function(memory, ft)\n    ensure_key(memory, ft)\n    return memory[ft][\"singleton\"]\n  end\n}\n\nreturn scope\n"
  },
  {
    "path": "lua/iron/util/os.lua",
    "content": "local checks = {}\n\nchecks.is_windows = function()\n    return package.config:sub(1,1) == '\\\\'\nend\n\n\nchecks.has = function(feature)\n  return vim.api.nvim_call_function('has', {feature}) == 1\nend\n\nreturn checks\n"
  },
  {
    "path": "lua/iron/util/tables.lua",
    "content": "-- luacheck: globals vim\nlocal fns = {}\n\nfns.extend = function(...)\n  local tbl = {}\n  local tbls = {n = select(\"#\", ...), ...}\n  for ix=1, tbls.n do\n    local itm = tbls[ix]\n    if itm ~= nil then\n      if type(itm) == \"table\" then\n        vim.list_extend(tbl, itm)\n      else\n        table.insert(tbl, itm)\n      end\n    end\n  end\n\n  return tbl\nend\n\n\nreturn fns\n"
  },
  {
    "path": "lua/iron/view.lua",
    "content": "-- luacheck: globals unpack vim\nlocal view = {}\n\n--- Private functions\nlocal with_defaults = function(options)\n  return vim.tbl_extend(\"keep\", options or {}, {\n    winfixwidth = true,\n    winfixheight = true\n  })\nend\n\nlocal nested_modifier\n\nlocal with_nested_metatable = function(tbl)\n  return setmetatable(tbl, {\n    __index = nested_modifier,\n    __call = function(_, arg, options)\n      return tbl:mode(arg, options)\n    end\n  })\nend\n\nnested_modifier = function(tbl, key)\n  local new = vim.deepcopy(tbl)\n  table.insert(new, key)\n\n  return with_nested_metatable(new)\nend\n\nlocal size_extractor = function(size, vertical, ...)\n  local new_size\n  if type(size) == \"string\" and string.find(size, \"%%\") then\n    local pct = size:gsub(\"%%\", \"\")\n    pct = tonumber(pct)\n    local base\n    if vertical then\n      base = vim.o.columns\n    else\n      base = vim.o.lines\n    end\n    new_size = math.floor((base * pct) / 100.0)\n  elseif type(size) == \"function\" then\n    new_size = size(vertical, ...)\n  elseif size == nil then\n    new_size = 0\n  elseif 1 > size and size > 0 then\n    local base\n    if vertical then\n      base = vim.o.columns\n    else\n      base = vim.o.lines\n    end\n    new_size = math.floor(base * size)\n  else\n    new_size = size\n  end\n  return new_size\nend\n\nview.helpers = {}\n\n--- Returns proportional difference between an object and the editor size\n-- with the offset adjusting the distance on both sides.\n-- Use offset 0.5 for centralization\n-- @tparam number offset proportion of distribution (0.5 is centralized)\n-- @tparam boolean vertical Whether the oritentation is vertical or not\n-- @tparam number sz size of the object\n-- @treturn number placement index\n-- @treturn function\nview.helpers.proportion = function(offset)\n  return function(vertical, sz)\n    local attr = vertical and \"columns\" or \"lines\"\n    return math.ceil(vim.o[attr] * offset - sz * offset)\n  end\nend\n\n--- Flips the orientation from top/left to bottom/right\n-- @tparam number offset in columns/lines\n-- @tparam boolean vertical Whether the oritentation is vertical or not\n-- @tparam number sz size of the object\n-- @treturn number placement index\n-- @treturn function\nview.helpers.flip = function(offset)\n  return function(vertical, sz)\n    local attr = vertical and \"columns\" or \"lines\"\n    return math.ceil(vim.o[attr] - sz - offset)\n  end\nend\n\n--- Open a split window\n-- Takes the arguments to the split command as nested values (keys) of this table.\n-- @example view.split.vertical.botright(20)\n-- @tparam table data itself\n-- @tparam number|string|function size Either a number, a size in string or a function that returns the size\n-- @tparam number bufnr buffer handle\n-- @treturn number window id\n-- @treturn function the function that opens the window\nview.split = with_nested_metatable{ mode = function(data, size, options)\n  return function(bufnr)\n    local args = vim.list_slice(data, 1, #data)\n    local new_size = size_extractor(size, vim.tbl_contains(data, \"vertical\") or vim.tbl_contains(data, \"vert\"))\n\n    if size then\n      table.insert(args, tostring(new_size))\n    end\n    table.insert(args, \"split\")\n\n    vim.cmd(table.concat(args, \" \"))\n    vim.api.nvim_set_current_buf(bufnr)\n\n    local winid = vim.fn.bufwinid(bufnr)\n    for opt, val in pairs(with_defaults(options)) do\n      vim.api.nvim_win_set_option(winid, opt, val)\n    end\n    return winid\n  end\nend\n}\n\n--- Used to open a float window\n-- @tparam table config parameters for the float window\n-- @tparam number buff buffer handle\n-- @treturn number window id\nview.openfloat = function(config, buff)\n  return vim.api.nvim_open_win(buff, false, config)\nend\n\n\n--- Opens a float at any point in the window\n-- @tparam table opts Options for calculating the repl size\n-- @tparam number|string|function opts.width width of the window\n-- @tparam number|string|function opts.height height of the window\n-- @tparam number|string|function opts.w_offset horizontal offset from the bottom-right corner\n-- @tparam number|string|function opts.h_offset vertical offset from the bottom-right corner\n-- @treturn table configuration for the float window\n-- @treturn function\nview.offset = function(opts)\n  return function()\n    local new_w_size = size_extractor(opts.width, true)\n    local new_h_size = size_extractor(opts.height, false)\n    local new_w_offset = size_extractor(opts.w_offset, true, new_w_size)\n    local new_h_offset = size_extractor(opts.h_offset, false, new_h_size)\n\n    return {\n      relative = \"editor\",\n      width = new_w_size,\n      height = new_h_size,\n      row = new_h_offset,\n      col = new_w_offset\n    }\n  end\nend\n\n--- Opens a float pinned to the top\n-- @tparam number|string|function size height of the window\n-- @treturn function\nview.top = function(size)\n  return view.offset{width = vim.o.columns, height = size}\nend\n\n--- Opens a float pinned to the bottom\n-- @tparam number|string|function size height of the window\n-- @treturn function\nview.bottom = function(size)\n  return view.offset{width = vim.o.columns, height = size, h_offset = view.helpers.flip(0)}\nend\n\n--- Opens a float pinned to the right\n-- @tparam number|string|function size width of the window\n-- @treturn function\nview.right = function(size)\n  return view.offset{width = size, height = vim.o.lines, w_offset = view.helpers.flip(0)}\nend\n\n--- Opens a float pinned to the left\n-- @tparam number|string|function size width of the window\n-- @treturn function\nview.left = function(size)\n  return view.offset{width = size, height = vim.o.lines}\nend\n\n--- Opens a repl in the middle of the screen\n-- @tparam number|string|function width width of the window\n-- @tparam number|string|function height height of the window. If null will use `width` for this size\n-- @treturn function\nview.center = function(width, height)\n  return view.offset{\n    width = width,\n    height = height or width,\n    w_offset = view.helpers.proportion(0.5),\n    h_offset = view.helpers.proportion(0.5)\n  }\nend\n\nview.curry = setmetatable({}, {\n  __index = function(_, key)\n    if  view[key] == nil then\n      error(\"Function `view.\" .. key .. \"` does not exist.\")\n    end\n    vim.deprecate(\"view.curry.\" .. key, \"view.\" .. key, \"3.2\", \"iron.nvim\")\n    return view[key]\n  end\n})\n\nreturn view\n"
  },
  {
    "path": "lua/iron/visibility.lua",
    "content": "-- luacheck: globals unpack vim\nlocal visibility = {}\n\n--- Show hidden window\n-- Creates a window for a buffer if it was previously\n-- hidden by nvim_win_hide, otherwise does nothing.\n-- @return window handle\n-- @treturn boolean wither the window was hidden or not\nlocal show_hidden = function(bufid, showfn)\n  local was_hidden = false\n  local window = vim.fn.bufwinid(bufid)\n\n  if window == -1 then\n    was_hidden = true\n    window = showfn()\n  end\n\n  return window, was_hidden\nend\n\nvisibility.single = function(bufid, showfn)\n  show_hidden(bufid, showfn)\nend\n\nvisibility.toggle = function(bufid, showfn)\n  local window, was_hidden = show_hidden(bufid, showfn)\n  if not was_hidden then\n    vim.api.nvim_win_hide(window)\n  end\nend\n\nvisibility.focus = function(bufid, showfn)\n  local window = show_hidden(bufid, showfn)\n  vim.api.nvim_set_current_win(window)\nend\n\nreturn visibility\n"
  },
  {
    "path": "spec/iron/core_spec.lua",
    "content": "-- luacheck: globals insulate setup describe it assert mock\n-- luacheck: globals before_each after_each\n\ninsulate(\"About #iron functionality\", function()\n  local tbl = require('iron.util.tables')\n  before_each(function()\n    _G.vim = mock({\n      api = {\n        nvim_call_function = function(_, _) return 1 end,\n        nvim_command = function(_) return \"\" end,\n        nvim_get_option = function(_) return \"\" end,\n        nvim_get_var = function(_) return \"\" end,\n        nvim_create_namespace = function(_) return 1000 end,\n        nvim_set_hl_ns = function(_) return nil end,\n        nvim_set_hl = function(_) return nil end,\n        nvim_err_writeln = function(_) return nil end,\n      },\n      fn = {\n        executable = function(_) return true end\n      }\n    })\n\n    _G.os = mock({\n      execute = function(_) return 0 end,\n    })\n  end)\n\n  after_each(function()\n     package.loaded['iron'] = nil\n     package.loaded['iron.config'] = nil\n     package.loaded['iron.core'] = nil\n   end)\n\n  describe(\"dynamic #config\", function()\n    it(\"is not called on a stored config\", function()\n      local iron = require('iron')\n      iron.config.stuff = 1\n      local _ = iron.config.stuff\n      assert.stub(_G.vim.api.nvim_get_var).was_called(0)\n    end)\n  end)\n\n  describe(\"#core functions\", function()\n    it(\"repl_for\", function()\n      local iron = require('iron')\n      iron.ll.ensure_repl_exists = mock(function() return {bufnr = 1}, true end)\n      iron.core.repl_for(\"python\")\n      assert.spy(_G.vim.api.nvim_command).was_called(1)\n    end)\n\n    it(\"repl_for if repl exists\", function()\n      local iron = require('iron')\n      iron.ll.ensure_repl_exists = mock(function() return {bufnr = 1}, true end)\n      iron.config.visibility = mock(function() end)\n      iron.core.repl_for(\"python\")\n      assert.spy(_G.vim.api.nvim_command).was_called(1)\n      assert.spy(iron.config.visibility).was_called(0)\n\n      iron.ll.ensure_repl_exists = mock(function() return {bufnr = 1}, false end)\n      iron.core.repl_for(\"python\")\n      assert.spy(iron.config.visibility).was_called(1)\n\n    end)\n  end)\nend)\n"
  },
  {
    "path": "spec/iron/fts/common_spec.lua",
    "content": "-- luacheck: globals insulate setup describe it assert mock\n-- luacheck: globals before_each after_each\n\n\ninsulate(\"On fthelper\", function()\n  local fts = require(\"iron.fts.common\").functions\n\n  describe(\"the #format function\", function()\n\n    it(\"should fail on string input\", function()\n        assert.has.errors(function () fts.format({}, \"\") end)\n      end)\n\n    it(\"should not add a new line on #empty lines input\", function()\n      assert.are.same(fts.format({}, {}), {})\n      end)\n\n    it(\"should not add a new empty line if the last one is an #empty line\", function()\n      assert.are.same(fts.format({}, {\"asdf\", \"\"}), {\"asdf\", \"\\13\"})\n      end)\n\n    it(\"should not add a new line if the input contains only one line\", function()\n      assert.are.same(fts.format({}, {\"asdf\"}), {\"asdf\\13\"})\n      end)\n\n\n    it(\"should add a new line if the input contains more than one line\", function()\n      assert.are.same(fts.format({}, {\"asdf\", \"qwer\"}), {\"asdf\", \"qwer\\13\"})\n      end)\n\n    it(\"should use supplied #format function if one is supplied\", function()\n      local f = mock(function(lns)\n        return lns\n      end)\n\n      assert.are.same(fts.format({format = f}, {\"1\", \"2\"}), {\"1\", \"2\"})\n\n      assert.stub(f).was_called(1)\n\n\n\n    end)\n\n    it(\"should #wrap the lines with whatever supplied enclosing pairs\", function()\n      assert.are.same(\n        fts.format({open = \"{\", close = \"}\"}, {\"asdf\", \"qwer\"}),\n        {\"{\", \"asdf\", \"qwer\", \"}\\13\"}\n      )\n\n      assert.are.same(\n        fts.format({open = \"\\x1b[200~\", close = \"\\x1b[201~\"}, {\"asdf\", \"qwer\"}),\n        {\"\\x1b[200~\", \"asdf\", \"qwer\", \"\\x1b[201~\\13\"}\n      )\n\n      assert.are.same(\n        fts.format({open = \"\\27[200~\", close = \"\\27[201~\"}, {\"asdf\", \"qwer\"}),\n        {\"\\27[200~\", \"asdf\", \"qwer\", \"\\27[201~\\13\"}\n      )\n      end)\n  end)\nend)\n"
  },
  {
    "path": "spec/iron/util/tables_spec.lua",
    "content": "-- luacheck: globals insulate setup describe it assert mock\n-- luacheck: globals before_each after_each\n\ninsulate(\"On #tables code\", function()\n  local fn = require('iron.util.tables')\n\n  describe(\"#get\", function()\n    it(\"should return nil if key doesn't exist\", function()\n      assert.are_same(nil, fn.get({}, \"key\"))\n      end)\n\n    it(\"should return nil if map is nil\", function()\n      assert.are_same(nil, fn.get(nil, \"key\"))\n      end)\n\n    it(\"should return nil if map is not a table\", function()\n      assert.are_same(nil, fn.get(0, \"key\"))\n      end)\n\n    it(\"should return value otherwise\", function()\n      assert.are_same(0, fn.get({key = 0}, \"key\"))\n      end)\n    end)\n\nend)\n"
  }
]