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