Repository: nvim-lua/plenary.nvim
Pull request #442 (2023-01-06 14:13:29)

chore: drop scratch dir


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index ced7f59..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,7 +0,0 @@
-## Pre-Alpha
-- Change the keys in tables returned by functions in the `plenary.window.float` module:
-    - `buf` -> `bufnr`
-    - `minor_buf` -> `minor_bufnr`
-    - `border_buf` -> `border_bufnr`
-    - `win` -> `win_id`
-    - `minor_win` -> `minor_win_id`
diff --git a/data/plenary/filetypes/builtin.lua b/data/plenary/filetypes/builtin.lua
index 8940a58..29af499 100644
--- a/data/plenary/filetypes/builtin.lua
+++ b/data/plenary/filetypes/builtin.lua
@@ -27,6 +27,7 @@ return {
     ['erb'] = 'eruby',
     ['ex'] = 'elixir',
     ['exs'] = 'elixir',
+    ['fish'] = 'fish',
     ['fnl'] = 'fennel',
     ['gd'] = 'gdscript',
     ['gql'] = 'graphql',
@@ -41,6 +42,7 @@ return {
     ['nix'] = 'nix',
     ['plist'] = 'xml',
     ['purs'] = 'purescript',
+    ['r'] = 'r',
     ['res'] = 'rescript',
     ['resi'] = 'rescript',
     ['rkt'] = 'racket',
diff --git a/lua/luassert/assert.lua b/lua/luassert/assert.lua
index e0e2c89..7fe7569 100644
--- a/lua/luassert/assert.lua
+++ b/lua/luassert/assert.lua
@@ -42,7 +42,7 @@ local __state_meta = {
       local arguments = util.make_arglist(...)
       local val, retargs = assertion.callback(self, arguments, util.errorlevel())
 
-      if not val == self.mod then
+      if (not val) == self.mod then
         local message = assertion.positive_message
         if not self.mod then
           message = assertion.negative_message
diff --git a/lua/luassert/assertions.lua b/lua/luassert/assertions.lua
index 19d056a..e5083c3 100644
--- a/lua/luassert/assertions.lua
+++ b/lua/luassert/assertions.lua
@@ -238,7 +238,9 @@ local function error_matches(state, arguments, level)
   end
 
   -- err_actual must be (convertible to) a string
-  if util.hastostring(err_actual) then
+  if util.hastostring(err_actual) or
+     type(err_actual) == "number" or
+     type(err_actual) == "boolean" then
     err_actual = tostring(err_actual)
     retargs[1] = err_actual
   end
diff --git a/lua/luassert/formatters/init.lua b/lua/luassert/formatters/init.lua
index 3071e11..0ff67c9 100644
--- a/lua/luassert/formatters/init.lua
+++ b/lua/luassert/formatters/init.lua
@@ -3,22 +3,28 @@ local assert = require('luassert.assert')
 local match = require('luassert.match')
 local util = require('luassert.util')
 
-local colors = setmetatable({
-  none = function(c) return c end
-},{ __index = function(self, key)
+local isatty, colors do
   local ok, term = pcall(require, 'term')
-  local isatty = io.type(io.stdout) == 'file' and ok and term.isatty(io.stdout)
-  if not ok or not isatty or not term.colors then
-    return function(c) return c end
+  isatty = io.type(io.stdout) == 'file' and ok and term.isatty(io.stdout)
+  if not isatty then
+    local isWindows = package.config:sub(1,1) == '\\'
+    if isWindows and os.getenv("ANSICON") then
+      isatty = true
+    end
   end
-  return function(c)
-    for token in key:gmatch("[^%.]+") do
-      c = term.colors[token](c)
+
+  colors = setmetatable({
+    none = function(c) return c end
+  },{ __index = function(self, key)
+    return function(c)
+      for token in key:gmatch("[^%.]+") do
+        c = term.colors[token](c)
+      end
+      return c
     end
-    return c
   end
+  })
 end
-})
 
 local function fmt_string(arg)
   if type(arg) == "string" then
@@ -122,7 +128,7 @@ local function fmt_table(arg, fmtargs)
   local tmax = assert:get_parameter("TableFormatLevel")
   local showrec = assert:get_parameter("TableFormatShowRecursion")
   local errchar = assert:get_parameter("TableErrorHighlightCharacter") or ""
-  local errcolor = assert:get_parameter("TableErrorHighlightColor") or "none"
+  local errcolor = assert:get_parameter("TableErrorHighlightColor")
   local crumbs = fmtargs and fmtargs.crumbs or {}
   local cache = {}
   local type_desc
@@ -246,4 +252,4 @@ assert:add_formatter(fmt_arglist)
 assert:set_parameter("TableFormatLevel", 3)
 assert:set_parameter("TableFormatShowRecursion", false)
 assert:set_parameter("TableErrorHighlightCharacter", "*")
-assert:set_parameter("TableErrorHighlightColor", "none")
+assert:set_parameter("TableErrorHighlightColor", isatty and "red" or "none")
diff --git a/lua/luassert/languages/en.lua b/lua/luassert/languages/en.lua
index c8bcc38..0d84b6d 100644
--- a/lua/luassert/languages/en.lua
+++ b/lua/luassert/languages/en.lua
@@ -34,11 +34,11 @@ s:set("assertion.called_at_most.positive", "Expected to be called at most %s tim
 s:set("assertion.called_more_than.positive", "Expected to be called more than %s time(s), but was called %s time(s)")
 s:set("assertion.called_less_than.positive", "Expected to be called less than %s time(s), but was called %s time(s)")
 
-s:set("assertion.called_with.positive", "Function was not called with the arguments")
-s:set("assertion.called_with.negative", "Function was called with the arguments")
+s:set("assertion.called_with.positive", "Function was never called with matching arguments.\nCalled with (last call if any):\n%s\nExpected:\n%s")
+s:set("assertion.called_with.negative", "Function was called with matching arguments at least once.\nCalled with (last matching call):\n%s\nDid not expect:\n%s")
 
-s:set("assertion.returned_with.positive", "Function was not returned with the arguments")
-s:set("assertion.returned_with.negative", "Function was returned with the arguments")
+s:set("assertion.returned_with.positive", "Function never returned matching arguments.\nReturned (last call if any):\n%s\nExpected:\n%s")
+s:set("assertion.returned_with.negative", "Function returned matching arguments at least once.\nReturned (last matching call):\n%s\nDid not expect:\n%s")
 
 s:set("assertion.returned_arguments.positive", "Expected to be called with %s argument(s), but was called with %s")
 s:set("assertion.returned_arguments.negative", "Expected not to be called with %s argument(s), but was called with %s")
diff --git a/lua/luassert/util.lua b/lua/luassert/util.lua
index e2e9a27..da2f247 100644
--- a/lua/luassert/util.lua
+++ b/lua/luassert/util.lua
@@ -89,7 +89,7 @@ function util.deepcopy(t, deepmt, cache)
     copy[k] = (spy.is_spy(v) and v or util.deepcopy(v, deepmt, cache))
   end
   if deepmt then
-    debug.setmetatable(copy, util.deepcopy(debug.getmetatable(t, nil, cache)))
+    debug.setmetatable(copy, util.deepcopy(debug.getmetatable(t), false, cache))
   else
     debug.setmetatable(copy, debug.getmetatable(t))
   end
@@ -274,6 +274,7 @@ end
 function util.callable(object)
   return type(object) == "function" or type((debug.getmetatable(object) or {}).__call) == "function"
 end
+
 -----------------------------------------------
 -- Checks an element has tostring.
 -- The type must either be a string or have a metatable
diff --git a/lua/plenary/busted.lua b/lua/plenary/busted.lua
index 6d1e91e..b827ff8 100644
--- a/lua/plenary/busted.lua
+++ b/lua/plenary/busted.lua
@@ -218,9 +218,9 @@ mod.run = function(file)
   print("\n" .. HEADER)
   print("Testing: ", file)
 
-  local ok, msg = pcall(dofile, file)
+  local loaded, msg = loadfile(file)
 
-  if not ok then
+  if not loaded then
     print(HEADER)
     print "FAILED TO LOAD FILE"
     print(color_string("red", msg))
@@ -232,33 +232,37 @@ mod.run = function(file)
     end
   end
 
-  -- If nothing runs (empty file without top level describe)
-  if not results.pass then
-    if is_headless then
-      return vim.cmd "0cq"
-    else
-      return
+  coroutine.wrap(function()
+    loaded()
+
+    -- If nothing runs (empty file without top level describe)
+    if not results.pass then
+      if is_headless then
+        return vim.cmd "0cq"
+      else
+        return
+      end
     end
-  end
 
-  mod.format_results(results)
+    mod.format_results(results)
 
-  if #results.errs ~= 0 then
-    print("We had an unexpected error: ", vim.inspect(results.errs), vim.inspect(results))
-    if is_headless then
-      return vim.cmd "2cq"
-    end
-  elseif #results.fail > 0 then
-    print "Tests Failed. Exit: 1"
+    if #results.errs ~= 0 then
+      print("We had an unexpected error: ", vim.inspect(results.errs), vim.inspect(results))
+      if is_headless then
+        return vim.cmd "2cq"
+      end
+    elseif #results.fail > 0 then
+      print "Tests Failed. Exit: 1"
 
-    if is_headless then
-      return vim.cmd "1cq"
-    end
-  else
-    if is_headless then
-      return vim.cmd "0cq"
+      if is_headless then
+        return vim.cmd "1cq"
+      end
+    else
+      if is_headless then
+        return vim.cmd "0cq"
+      end
     end
-  end
+  end)()
 end
 
 return mod
diff --git a/scratch/_reference_count.lua b/scratch/_reference_count.lua
deleted file mode 100644
index 7b0e15b..0000000
--- a/scratch/_reference_count.lua
+++ /dev/null
@@ -1,231 +0,0 @@
--------------------------------------------------------------------------------
--- This module implements a function that traverses all live objects.
--- You can implement your own function to pass as a parameter of traverse
--- and give you the information you want. As an example we have implemented
--- countreferences and findallpaths
---
--- Alexandra Barros - 2006.03.15
--------------------------------------------------------------------------------
-
-module("gc", package.seeall)
-
-local List = {}
-
-function List.new ()
-	return {first = 0, last = -1}
-end
-
-function List.push (list, value)
-	local last = list.last + 1
-    list.last = last
-    list[last] = value
-end
-
-function List.pop (list)	
-    local first = list.first
-    if first > list.last then error("list is empty") end
-    local value = list[first]
-    list[first] = nil        
-    list.first = first + 1
-    return value
-end
-
-function List.isempty (list)
-	return list.first > list.last
-end
-
--- Counts all references for a given object
-function countreferences(value)
-	local count = -1 
-	local f = function(from, to, how, v)
-		if to == value then 
-			count = count + 1
-		end 
-	end	
-	traverse({edge=f}, {count, f})
-	return count
-end
-
--- Prints all paths to an object
-function findallpaths(obj)
-	
-	local comefrom = {}
-	local f = function(from, to, how, value)
-		if not comefrom[to] then comefrom[to] = {} end
-		table.insert(comefrom[to], 1, {f = from, h = how, v=value})		
-	end
-	
-	traverse({edge=f}, {comefrom, f})
-	
-	
-	local function printpath(to)
-		if not to or comefrom[to].visited or to == _G then
-			print("-----")
-			return
-		end
-		comefrom[to].visited = true
-		for i=1, #comefrom[to] do
-			local tfrom = comefrom[to][i].f
-			print("from: ", vim.inspect(tfrom, { newline = '|' }), "\nhow:", comefrom[to][i].h,
-					"\nvalue:", comefrom[to][i].v)
-			printpath(tfrom)
-		end			
-	end
-	
-	printpath(obj)
-	
-end
-
--- Main function
--- 'funcs' is a table that contains a funcation for every lua type and also the
--- function edge edge (traverseedge).
-function traverse(funcs, ignoreobjs)
-
-	-- The keys of the marked table are the objetcts (for example, table: 00442330).
-	-- The value of each key is true if the object has been found and false
-	-- otherwise.
-	local env = {marked = {}, list=List.new(), funcs=funcs}
-	
-	if ignoreobjs then
-		for i=1, #ignoreobjs do
-			env.marked[ignoreobjs[i]] = true
-		end
-	end
-	
-	env.marked["gc"] = true
-	env.marked[gc] = true
-	
-	-- marks and inserts on the list
-	edge(env, nil, "_G", "isname", nil)
-	edge(env, nil, _G, "key", "_G")
-
-	-- traverses the active thread
-	-- inserts the local variables
-	-- interates over the function on the stack, starting from the one that
-	-- called traverse
-	for i=2, math.huge do
-		local info = debug.getinfo(i, "f") 
-		if not info then break end 
-		for j=1, math.huge do
-			local n, v = debug.getlocal(i, j)
-			if not n then break end
-		
-			edge(env, nil, n, "isname", nil)
-			edge(env, nil, v, "local", n)
-		end
-	end
-	
- 	while not List.isempty(env.list) do	 		
- 	
-		local obj = List.pop(env.list)
- 		local t = type(obj)
-        if not gc["traverse" .. t] then
-          error("Could not find traverse " .. t)
-        end
-
- 		gc["traverse" .. t](env, obj)
-			
-	end			
-	
-end
-
-function traversetable(env, obj)
-	
-	local f = env.funcs.table
-	if f then f(obj) end
-	
-	for key, value in pairs(obj) do	
-		edge(env, obj, key, "iskey", nil)
-		edge(env, obj, value, "key", key)		
-	end
-	
-	local mtable = debug.getmetatable(obj)
-	if mtable then edge(env, obj, mtable, "ismetatable", nil) end
-
-end
-			
-function traversestring(env, obj)
-	local f = env.funcs.string
-	if f then f(obj) end
-	
-end
-
-function traverseuserdata(env, obj)
-	local f = env.funcs.userdata
-	if f then f(obj) end
-	
-	local mtable = debug.getmetatable(obj)
-	if mtable then edge(env, obj, mtable, "ismetatable", nil) end
-	
-	local fenv = debug.getfenv(obj)
-	if fenv then edge(env, obj, fenv, "environment", nil) end
-	
-end
-
-function traversefunction(env, obj)
-	local f = env.funcs.func
-	if f then f(obj) end
-	
-	-- gets the upvalues
-	local i = 1	
-	while true do
-		local n, v = debug.getupvalue(obj, i)
-		if not n then break end -- when there is no upvalues
-		edge(env, obj, n, "isname", nil)
-		edge(env, obj, v, "upvalue", n)
-		i = i + 1
-	end
-		
-	local fenv = debug.getfenv(obj)
-	edge(env, obj, fenv, "enviroment", nil)
-	
-end
-
-function traversecdata(env, t)
-  -- print(env, t)
-end
-			
-function traversethread(env, t)
-	local f = env.funcs.thread
-	if f then f(t) end
-	
-	for i=1, math.huge do
-		local info = debug.getinfo(t, i, "f") 
-		if not info then break end 
-		for j=1, math.huge do
-			local n, v = debug.getlocal(t, i , j)
-			if not n then break end
-			print(n, v)
-		
-			edge(env, nil, n, "isname", nil)
-			edge(env, nil, v, "local", n)
-		end
-	end
-	
-	local fenv = debug.getfenv(t)
-	edge(env, t, fenv, "enviroment", nil)
-	
-end
-
-
--- 'how' is a string that identifies the content of 'to' and 'value':
--- 		if 'how' is "iskey", then 'to' é is a key and 'value' is nil.
--- 		if 'how' is "key", then 'to' is an object and 'value' is the name of the
---		key.
-function edge(env, from, to, how, value)
-	
-	local t = type(to)	
-	
-	if to and (t~="boolean") and (t~="number") and (t~="new") then
-		-- If the destination object has not been found yet
-		if not env.marked[to] then 
-			env.marked[to] = true
-			List.push(env.list, to) -- puts on the list to be traversed
-		end
-		
-		local f = env.funcs.edge
-		if f then f(from, to, how, value) end
-		
-	end	
-	
-end
diff --git a/scratch/coroutine_examples.lua b/scratch/coroutine_examples.lua
deleted file mode 100644
index 5f82495..0000000
--- a/scratch/coroutine_examples.lua
+++ /dev/null
@@ -1,14 +0,0 @@
-
-local f = function(xyz)
-  print('calling 1', xyz)
-  local foo = coroutine.yield()
-  print('calling 2', foo)
-  return 5
-end
-
-local x = coroutine.wrap(f)
-
-x('bar')
-x('zap')
--- x()
--- x()
diff --git a/scratch/iterators.lua b/scratch/iterators.lua
deleted file mode 100644
index ebc1ea2..0000000
--- a/scratch/iterators.lua
+++ /dev/null
@@ -1,4 +0,0 @@
-local i = require('plenary.iterators')
-
-dump(i.split("  hello person dude ", " "):tolist())
--- dump(("hello person"):find("person"))
diff --git a/scratch/job_graveyard.lua b/scratch/job_graveyard.lua
deleted file mode 100644
index 5a90085..0000000
--- a/scratch/job_graveyard.lua
+++ /dev/null
@@ -1,55 +0,0 @@
-
-function Job.accumulate_results(results)
-  return function(err, data)
-    if data == nil then
-      if results[#results] == '' then
-        table.remove(results, #results)
-      end
-
-      return
-    end
-
-    if results[1] == nil then
-      results[1] = ''
-    end
-
-    -- Get rid of pesky \r
-    data = data:gsub("\r", "")
-
-    local line, start, found_newline
-    while true do
-      start = string.find(data, "\n") or #data
-      found_newline = string.find(data, "\n")
-
-      line = string.sub(data, 1, start)
-      data = string.sub(data, start + 1, -1)
-
-      line = line:gsub("\r", "")
-      line = line:gsub("\n", "")
-
-      results[#results] = (results[#results] or '') .. line
-
-      if found_newline then
-        table.insert(results, '')
-      else
-        break
-      end
-    end
-
-    -- if found_newline and results[#results] == '' then
-    --   table.remove(results, #results)
-    -- end
-
-    -- if string.find(data, "\n") then
-    --   for _, line in ipairs(vim.fn.split(data, "\n")) do
-    --     line = line:gsub("\n", "")
-    --     line = line:gsub("\r", "")
-
-    --     table.insert(results, line)
-    --   end
-    -- else
-    --   results[#results] = results[#results] .. data
-    -- end
-  end
-end
-
diff --git a/scratch/job_memory_leaker.lua b/scratch/job_memory_leaker.lua
deleted file mode 100644
index 3d825f8..0000000
--- a/scratch/job_memory_leaker.lua
+++ /dev/null
@@ -1,37 +0,0 @@
-require('plenary.reload').reload_module('plenary')
-
-local Job = require('plenary.job')
-
-print("STARTING:", start_mem)
-
-collectgarbage('collect')
-start_mem = collectgarbage('count')
-local inter_mem = {}
-local final_mem = nil
-local after_mem = nil
-
-for i = 1, 10 do
-  local x = Job:new {
-    command = 'fdfind',
-    args = nil,
-    cwd = '/home/tj/',
-
-    enable_recording = false,
-    -- writer = writer,
-
-    -- on_stdout = on_output,
-    -- on_stderr = on_output,
-
-    on_exit = function()
-      table.insert(inter_mem, collectgarbage('count'))
-    end,
-  }:sync()
-end
-
-final_mem = collectgarbage('count')
-collectgarbage('collect')
-after_mem = collectgarbage('count')
-
-print("AFTER   :", start_mem)
-print(vim.inspect(inter_mem))
-print(final_mem, after_mem)
diff --git a/scratch/memory_profiler.lua b/scratch/memory_profiler.lua
deleted file mode 100644
index 1be8004..0000000
--- a/scratch/memory_profiler.lua
+++ /dev/null
@@ -1,80 +0,0 @@
---
--- Show case of MemoryReferenceInfo.lua.
---
--- @filename  Example.lua
--- @author    WangYaoqi
--- @date      2017-05-04
-
-local mri = require("plenary.profile.memory_profiler")
-
--- Set config.
-mri.m_cConfig.m_bAllMemoryRefFileAddTime = false
---mri.m_cConfig.m_bSingleMemoryRefFileAddTime = false
---mri.m_cConfig.m_bComparedMemoryRefFileAddTime = false
-
--- 打印当前 Lua 虚拟机的所有内存引用快照到文件(或者某个对象的所有引用信息快照)到本地文件。
--- strSavePath - 快照保存路径，不包括文件名。
--- strExtraFileName - 添加额外的信息到文件名，可以为 "" 或者 nil。
--- nMaxRescords - 最多打印多少条记录，-1 打印所有记录。
--- strRootObjectName - 遍历的根节点对象名称，"" 或者 nil 时使用 tostring(cRootObject)
--- cRootObject - 遍历的根节点对象，默认为 nil 时使用 debug.getregistry()。
--- MemoryReferenceInfo.m_cMethods.DumpMemorySnapshot(strSavePath, strExtraFileName, nMaxRescords, strRootObjectName, cRootObject)
-collectgarbage("collect")
-mri.m_cMethods.DumpMemorySnapshot("./", "1-Before", -1)
-
--- Add a global variable.
-local author = 
-{
-    Name = "yaukeywang",
-    Job = "Game Developer",
-    Hobby = "Game, Travel, Gym",
-    City = "Beijing",
-    Country = "China",
-    Ask = function (question)
-        return "My answer is for your question: " .. question .. "."
-    end
-}
-
-_G.Author = author
-
--- Dump memory snapshot again.
-collectgarbage("collect")
-mri.m_cMethods.DumpMemorySnapshot("./", "2-After", -1)
-
--- 打印当前 Lua 虚拟机中某一个对象的所有相关引用。
--- strSavePath - 快照保存路径，不包括文件名。
--- strExtraFileName - 添加额外的信息到文件名，可以为 "" 或者 nil。
--- nMaxRescords - 最多打印多少条记录，-1 打印所有记录。
--- strObjectName - 对象显示名称。
--- cObject - 对象实例。
--- MemoryReferenceInfo.m_cMethods.DumpMemorySnapshotSingleObject(strSavePath, strExtraFileName, nMaxRescords, strObjectName, cObject)
-collectgarbage("collect")
-mri.m_cMethods.DumpMemorySnapshotSingleObject("./", "SingleObjRef-Object", -1, "Author", _G.Author)
-
--- We can also find string references.
-collectgarbage("collect")
-mri.m_cMethods.DumpMemorySnapshotSingleObject("./", "SingleObjRef-String", -1, "Author Name", "yaukeywang")
-
--- 比较两份内存快照结果文件，打印文件 strResultFilePathAfter 相对于 strResultFilePathBefore 中新增的内容。
--- strSavePath - 快照保存路径，不包括文件名。
--- strExtraFileName - 添加额外的信息到文件名，可以为 "" 或者 nil。
--- nMaxRescords - 最多打印多少条记录，-1 打印所有记录。
--- strResultFilePathBefore - 第一个内存快照文件。
--- strResultFilePathAfter - 第二个用于比较的内存快照文件。
--- MemoryReferenceInfo.m_cMethods.DumpMemorySnapshotComparedFile(strSavePath, strExtraFileName, nMaxRescords, strResultFilePathBefore, strResultFilePathAfter)
-mri.m_cMethods.DumpMemorySnapshotComparedFile("./", "Compared", -1, "./LuaMemRefInfo-All-[1-Before].txt", "./LuaMemRefInfo-All-[2-After].txt")
-
--- 按照关键字过滤一个内存快照文件然后输出到另一个文件.
--- strFilePath - 需要被过滤输出的内存快照文件。
--- strFilter - 过滤关键字
--- bIncludeFilter - 包含关键字(true)还是排除关键字(false)来输出内容。
--- bOutputFile - 输出到文件(true)还是 console 控制台(false)。
--- MemoryReferenceInfo.m_cBases.OutputFilteredResult(strFilePath, strFilter, bIncludeFilter, bOutputFile)
--- Filter all result include keywords: "Author".
-mri.m_cBases.OutputFilteredResult("./LuaMemRefInfo-All-[2-After].txt", "Author", true, true)
-
--- Filter all result exclude keywords: "Author".
-mri.m_cBases.OutputFilteredResult("./LuaMemRefInfo-All-[2-After].txt", "Author", false, true)
-
--- All dump finished!
-print("Dump memory snapshot information finished!")
diff --git a/scratch/memory_tracker.lua b/scratch/memory_tracker.lua
deleted file mode 100644
index d9f23f8..0000000
--- a/scratch/memory_tracker.lua
+++ /dev/null
@@ -1,3 +0,0 @@
-local nvim_pid = 2201099 
-
-vim.api.nvim_buf_set_lines(981, 0, -1, false, vim.fn.systemlist({'pmap', tostring(nvim_pid), '-X'}))
diff --git a/scratch/minimal_init.vim b/scratch/minimal_init.vim
deleted file mode 100644
index 1a7af9b..0000000
--- a/scratch/minimal_init.vim
+++ /dev/null
@@ -1,6 +0,0 @@
-
-set rtp+=/home/tj/plugins/popup.nvim/
-set rtp+=/home/tj/plugins/plenary.nvim/
-set rtp+=/home/tj/plugins/telescope.nvim/
-
-nnoremap ,,x :luafile %<CR>
diff --git a/scratch/new_line_finder.lua b/scratch/new_line_finder.lua
deleted file mode 100644
index 39fdcf2..0000000
--- a/scratch/new_line_finder.lua
+++ /dev/null
@@ -1,114 +0,0 @@
-
-local nf_finder = function(data)
-  local results = {}
-
-  if data == nil then
-    if results[#results] == '' then
-      table.remove(results, #results)
-    end
-
-    return
-  end
-
-  local line, last_start, start, found_newline, result_index
-
-  last_start = 1
-  result_index = #results + 1
-  repeat
-    start = string.find(data, "\n", last_start, true) or #data
-    found_newline = start ~= #data
-
-    line = string.sub(data, last_start, start - 1)
-
-    if results[result_index] then
-      results[result_index] = results[result_index] .. line
-    else
-      results[result_index] = line
-    end
-
-    if found_newline then
-      result_index = result_index + 1
-    end
-
-    last_start = start + 1
-  until not found_newline
-
-  return results
-end
-
-local prev_nf_finder = function(data) -- {{{
-  local results = { '' }
-
-  if data == nil then
-    if results[#results] == '' then
-      table.remove(results, #results)
-    end
-
-    return
-  end
-
-  local line, last_start, start, found_newline
-
-  last_start = 1
-  repeat
-    start = string.find(data, "\n", last_start, true) or #data
-    found_newline = start ~= #data
-
-    line = string.sub(data, last_start, start - 1)
-
-    results[#results] = (results[#results] or '') .. line
-
-    if found_newline then
-      table.insert(results, '')
-    end
-
-    last_start = start + 1
-  until not found_newline
-
-  return results
-end -- }}}
-local old_nf_finder = function(data) -- {{{
-  local results = {}
-
-  if data == nil then
-    if results[#results] == '' then
-      table.remove(results, #results)
-    end
-
-    return
-  end
-
-  local line, start, found_newline
-  repeat
-    start = string.find(data, "\n", nil, true) or #data
-    found_newline = string.find(data, "\n", nil, true)
-
-    line = string.sub(data, 1, start - 1)
-    data = string.sub(data, start + 1, -1)
-
-    line = line:gsub("\r", "")
-
-    results[#results] = (results[#results] or '') .. line
-
-    if found_newline then
-      table.insert(results, '')
-    end
-  until not found_newline
-end -- }}}
-
-local disp_result = false
-local to_test = vim.fn.system('fdfind')
-
-
-if disp_result then
-  print(vim.inspect(nf_finder(to_test)))
-else
-  local test_amount = 100
-  print(#to_test * test_amount)
-  print(require('plenary.profile').benchmark(test_amount, nf_finder, to_test))
-  print(require('plenary.profile').benchmark(test_amount, prev_nf_finder, to_test))
-  print(require('plenary.profile').benchmark(test_amount, old_nf_finder, to_test))
-end
--- print(require('plenary.profile').benchmark(100, nf_finder, to_test))
--- print(require('plenary.profile').benchmark(100, nf_finder, to_test))
--- print(require('plenary.profile').benchmark(100, nf_finder, to_test))
diff --git a/scratch/rotate_bench.lua b/scratch/rotate_bench.lua
deleted file mode 100644
index 2b6a9d3..0000000
--- a/scratch/rotate_bench.lua
+++ /dev/null
@@ -1,21 +0,0 @@
-local tbl = require('plenary/tbl')
-
-local vararg = require('plenary/vararg')
-local rotate = vararg.rotate
-local bench = require('plenary.profile').benchmark
-
-local function rotate_n(first, ...)
-  local args = tbl.pack(...)
-  args[#args+1] = first
-  return tbl.unpack(args)
-end
-
-local num = 2e7 -- 2e4
-
-print('rotate: ', bench(num, function()
-  local a, b, c, d, e, f, g = rotate(1, 2, 3, 4, 5, 6)
-end))
-
-print('rotate_n: ', bench(num, function()
-  local a, b, c, d, e, f, g = rotate_n(1, 2, 3, 4, 5, 6)
-end))
diff --git a/scratch/term_open_checker.lua b/scratch/term_open_checker.lua
deleted file mode 100644
index 28d101d..0000000
--- a/scratch/term_open_checker.lua
+++ /dev/null
@@ -1,73 +0,0 @@
-local bufnr = 463
-
-local Job  = require('plenary.job')
-
-local get_status = function(job_id)
-  return vim.fn.jobwait({job_id}, 0)[1]
-end
-
-local on_output = function(err, data)
-  vim.api.nvim_get_mode()
-
-  if err then
-    return
-  end
-
-  if data == nil then
-    return
-  end
-
-  -- Get rid of pesky \r
-  data = data:gsub("\r", "")
-
-  local line, start, found_newline
-  while true do
-    start = string.find(data, "\n") or #data
-    found_newline = string.find(data, "\n")
-
-    line = string.sub(data, 1, start)
-    data = string.sub(data, start + 1, -1)
-
-    line = line:gsub("\r", "")
-    line = line:gsub("\n", "")
-
-    -- results[#results] = (results[#results] or '') .. line
-    vim.api.nvim_buf_set_lines(bufnr, -2, -1, false, {
-      (vim.api.nvim_buf_get_lines(bufnr, -1, -1, false)[1] or '') .. line
-    })
-
-    if found_newline then
-      -- table.insert(results, '')
-      vim.api.nvim_buf_set_lines(bufnr, -1, -1, false, {''})
-    else
-      break
-    end
-  end
-end
-
-local runner = function()
-  -- local job_id = vim.fn.termopen("wget https://google.com -o ~/Downloads/tmp.html")
-  -- local job_id = vim.fn.termopen("sleep 100m")
-  local j = Job:new({
-    command = "bash",
-    -- args = {"-c", "wget https://google.com -o ~/Downloads/tmp.html"},
-    args = {"-c", "echo 'hello world'; sleep 2; echo 'done'"},
-    on_stdout = on_output,
-    on_stderr = on_output,
-  })
-
-  local next_j = Job:new({
-    command = "bash",
-    -- args = {"-c", "wget https://google.com -o ~/Downloads/tmp.html"},
-    args = {"-c", "echo 'second thing'; sleep 2; echo 'done part 2'"},
-    on_stdout = on_output,
-    on_stderr = on_output,
-  })
-
-  return Job.chain(j, next_j)
-end
-
-if false then
-  print(runner())
-  vim.wait(5000, function() return Job.chain_status(1) end)
-end


Test patch:
diff --git a/TESTS_README.md b/TESTS_README.md
index 1103ca2..955cdf9 100644
--- a/TESTS_README.md
+++ b/TESTS_README.md
@@ -34,11 +34,21 @@ The test **some test** checks that a functions output is as expected based on th
 
 # Running tests
 
-Run the test using `:PlenaryBustedTest <file>`. 
+Run the test using `:PlenaryBustedFile <file>`. 
 
 ```vimscript
 " Run the test in the current buffer
-:PlenaryBustedTest %
+:PlenaryBustedFile %
+" Run all tests in the directory "tests/plenary/"
+:PlenaryBustedDirectory tests/plenary/
+```
+
+Or you can run tests in headless mode to see output in terminal:
+
+```bash
+# run all tests in terminal
+cd plenary.nvim
+nvim --headless -c 'PlenaryBustedDirectory tests'
 ```
 
 # mocking with luassert
@@ -125,3 +135,19 @@ To test this in your `~/.config/nvim` configuration, try the suggested file stru
 lua/example/module.lua
 lua/spec/example/module_spec.lua
 ```
+
+# Asynchronous testing
+
+Tests run in a coroutine, which can be yielded and resumed. This can be used to
+test code that uses asynchronous Neovim functionalities. For example, this can
+be done inside a test:
+
+```lua
+local co = coroutine.running()
+vim.defer_fn(function()
+  coroutine.resume(co)
+end, 1000)
+--The test will reach here immediately.
+coroutine.yield()
+--The test will only reach here after one second, when the deferred function runs.
+```
diff --git a/scratch/busted_tester.lua b/scratch/busted_tester.lua
deleted file mode 100644
index cdc59d9..0000000
--- a/scratch/busted_tester.lua
+++ /dev/null
@@ -1,24 +0,0 @@
-local level = 2
-local info = debug.getinfo(1, 'Sf')
-local source = info.source
-
-local b = require('busted.core')()
-
-b.register('file', 'file', {})
-
-local testFileLoader = require 'busted.modules.standalone_loader'(b)
-testFileLoader(info, { verbose = nil })
-
-local execute = require('busted.execute')(b)
-
-print(vim.inspect(execute))
-print(vim.inspect(b))
-print("===")
-print(execute(1, {}))
-print("===")
--- execute(1, {})
-
--- print(vim.inspect(b.execute))
--- print(vim.inspect(b.execute('file', './tests/plenary/bu/simple_busted_spec.lua')))
--- require('busted.init')(b)
--- print(vim.inspect(b))
diff --git a/scratch/run_tester.lua b/scratch/run_tester.lua
deleted file mode 100644
index ef468de..0000000
--- a/scratch/run_tester.lua
+++ /dev/null
@@ -1,16 +0,0 @@
-
-local lu = require("plenary.luaunit")
-local test_harness = require("plenary.test_harness")
-
-require("tests.plenary.path_spec")
-
--- lu.LuaUnit.run("./tests/plenary/path_spec.lua")
--- lu.LuaUnit.run({"TestPath"})
-
-test_harness:run(0, 0, "TestPath")
-
-
-[[
-lua require("plenary.test_harness"):test_directory("luaunit", "./tests/plenary/lu/")
-lua require("plenary.test_harness"):test_directory("busted", "./tests/plenary/bu/")
-]]
diff --git a/scratch/window_test.lua b/scratch/window_test.lua
deleted file mode 100644
index be44d4b..0000000
--- a/scratch/window_test.lua
+++ /dev/null
@@ -1,60 +0,0 @@
---luacheck: ignore
-
-function CanWinBeHidden()
-  -- The answer is yes
-  -- Just keep track of the buffer ID
-
-  local what = "test string"
-  local bufnr = vim.api.nvim_create_buf(false, true)
-
-  -- TODO: Handle list of lines
-  vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, {what})
-
-  local win_id = vim.api.nvim_open_win(bufnr, true, {relative='win', row=3, col=3, width=40, height=3})
-  vim.api.nvim_win_close(win_id, false)
-end
-
-
-function CanWinBeReordered()
-  what = "test string"
-  buf_text = vim.api.nvim_create_buf(false, true)
-
-  buf_border = vim.api.nvim_create_buf(false, true)
-
-  -- TODO: Handle list of lines
-  vim.api.nvim_buf_set_lines(buf_text, 0, -1, true, {what})
-  vim.api.nvim_buf_set_lines(buf_border, 0, -1, true, {"====", "", "====="})
-
-  win_text = vim.api.nvim_open_win(buf_text, false, {relative='win', row=3, col=3, width=40, height=1})
-  win_border = vim.api.nvim_open_win(buf_border, false, {relative='win', row=2, col=3, width=40, height=3})
-
-  vim.api.nvim_win_close(win_text, false)
-  vim.api.nvim_win_close(win_border, false)
-
-  current_win_id = vim.fn.win_getid()
-  _ = {vim.fn.win_gotoid(win_text), vim.cmd("sleep 100m"), vim.fn.win_gotoid(current_win_id)}
-  _ = {vim.fn.win_gotoid(win_text), vim.cmd("redraw"), vim.fn.win_gotoid(current_win_id)}
-end
-
-function CanMakeBorders()
-  package.loaded['plenary.window.border'] = nil
-  package.loaded['plenary.popup'] = nil
-
-  Popup = require('plenary.popup').popup_create("Hello world", {
-    title = "Example",
-
-    line = 3,
-    col = 3,
-    pos = "topleft"
-  })
-end
-
-function CanDoTopWin()
-  package.loaded['plenary.window.border'] = nil
-  package.loaded['plenary.window.float'] = nil
-  package.loaded['plenary.popup'] = nil
-  package.loaded['plenary.run'] = nil
-
-  -- require('plenary.window.float').centered_with_top_win({"hello world", "this is TJ"})
-  require('plenary.run').with_displayed_output({"This is a comment", "At the top"}, "echo 'hello world'")
-end
diff --git a/tests/plenary/async_testing_spec.lua b/tests/plenary/async_testing_spec.lua
new file mode 100644
index 0000000..c1c991b
--- /dev/null
+++ b/tests/plenary/async_testing_spec.lua
@@ -0,0 +1,75 @@
+local Job = require "plenary.job"
+
+local Timing = {}
+
+function Timing:log(name)
+  self[name] = vim.loop.uptime()
+end
+
+function Timing:check(from, to, min_elapsed)
+  assert(self[from], "did not log " .. from)
+  assert(self[to], "did not log " .. to)
+  local elapsed = self[to] - self[from]
+  assert(
+    min_elapsed <= elapsed,
+    string.format("only took %s to get from %s to %s - expected at least %s", elapsed, from, to, min_elapsed)
+  )
+end
+
+describe("Async test", function()
+  it("can resume testing with vim.defer_fn", function()
+    local co = coroutine.running()
+    assert(co, "not running inside a coroutine")
+
+    local timing = setmetatable({}, { __index = Timing })
+
+    vim.defer_fn(function()
+      coroutine.resume(co)
+    end, 200)
+    timing:log "before"
+    coroutine.yield()
+    timing:log "after"
+    timing:check("before", "after", 0.1)
+  end)
+
+  it("can resume testing from job callback", function()
+    local co = coroutine.running()
+    assert(co, "not running inside a coroutine")
+
+    local timing = setmetatable({}, { __index = Timing })
+
+    Job:new({
+      command = "bash",
+      args = {
+        "-ce",
+        [[
+        sleep 0.2
+        echo hello
+        sleep 0.2
+        echo world
+        sleep 0.2
+        exit 42
+      ]],
+      },
+      on_stdout = function(_, data)
+        timing:log(data)
+      end,
+      on_exit = function(_, exit_status)
+        timing:log "exit"
+        --This is required so that the rest of the test will run in a proper context
+        vim.schedule(function()
+          coroutine.resume(co, exit_status)
+        end)
+      end,
+    }):start()
+    timing:log "job started"
+    local exit_status = coroutine.yield()
+    timing:log "job finished"
+    assert.are.equal(exit_status, 42)
+
+    timing:check("job started", "job finished", 0.3)
+    timing:check("job started", "hello", 0.1)
+    timing:check("hello", "world", 0.1)
+    timing:check("world", "job finished", 0.1)
+  end)
+end)
diff --git a/tests/plenary/scandir_spec.lua b/tests/plenary/scandir_spec.lua
index 0e30d5c..9c15808 100644
--- a/tests/plenary/scandir_spec.lua
+++ b/tests/plenary/scandir_spec.lua
@@ -26,7 +26,7 @@ describe("scandir", function()
     it("with cwd", function()
       local dirs = scan.scan_dir "."
       eq("table", type(dirs))
-      eq(true, contains(dirs, "./CHANGELOG.md"))
+      eq(true, contains(dirs, "./README.md"))
       eq(true, contains(dirs, "./LICENSE"))
       eq(true, contains(dirs, "./lua/plenary/job.lua"))
       eq(false, contains(dirs, "./asdf/asdf/adsf.lua"))
@@ -40,7 +40,7 @@ describe("scandir", function()
         end,
       })
       eq("table", type(dirs))
-      eq(true, contains(dirs, "./CHANGELOG.md"))
+      eq(true, contains(dirs, "./README.md"))
       eq(true, contains(dirs, "./LICENSE"))
       eq(true, contains(dirs, "./lua/plenary/job.lua"))
       eq(false, contains(dirs, "./asdf/asdf/adsf.lua"))
@@ -59,7 +59,7 @@ describe("scandir", function()
     it("with hidden files", function()
       local dirs = scan.scan_dir(".", { hidden = true })
       eq("table", type(dirs))
-      eq(true, contains(dirs, "./CHANGELOG.md"))
+      eq(true, contains(dirs, "./README.md"))
       eq(true, contains(dirs, "./lua/plenary/job.lua"))
       eq(true, contains(dirs, "./.gitignore"))
       eq(false, contains(dirs, "./asdf/asdf/adsf.lua"))
@@ -68,7 +68,7 @@ describe("scandir", function()
     it("with add directories", function()
       local dirs = scan.scan_dir(".", { add_dirs = true })
       eq("table", type(dirs))
-      eq(true, contains(dirs, "./CHANGELOG.md"))
+      eq(true, contains(dirs, "./README.md"))
       eq(true, contains(dirs, "./lua/plenary/job.lua"))
       eq(true, contains(dirs, "./lua"))
       eq(true, contains(dirs, "./tests"))
@@ -78,7 +78,7 @@ describe("scandir", function()
     it("with only directories", function()
       local dirs = scan.scan_dir(".", { only_dirs = true })
       eq("table", type(dirs))
-      eq(false, contains(dirs, "./CHANGELOG.md"))
+      eq(false, contains(dirs, "./README.md"))
       eq(false, contains(dirs, "./lua/plenary/job.lua"))
       eq(true, contains(dirs, "./lua"))
       eq(true, contains(dirs, "./tests"))
@@ -88,7 +88,6 @@ describe("scandir", function()
     it("until depth 1 is reached", function()
       local dirs = scan.scan_dir(".", { depth = 1 })
       eq("table", type(dirs))
-      eq(true, contains(dirs, "./CHANGELOG.md"))
       eq(true, contains(dirs, "./README.md"))
       eq(false, contains(dirs, "./lua"))
       eq(false, contains(dirs, "./lua/say.lua"))
@@ -99,7 +98,6 @@ describe("scandir", function()
     it("until depth 1 is reached and with directories", function()
       local dirs = scan.scan_dir(".", { depth = 1, add_dirs = true })
       eq("table", type(dirs))
-      eq(true, contains(dirs, "./CHANGELOG.md"))
       eq(true, contains(dirs, "./README.md"))
       eq(true, contains(dirs, "./lua"))
       eq(false, contains(dirs, "./lua/say.lua"))
@@ -110,7 +108,6 @@ describe("scandir", function()
     it("until depth 2 is reached", function()
       local dirs = scan.scan_dir(".", { depth = 2 })
       eq("table", type(dirs))
-      eq(true, contains(dirs, "./CHANGELOG.md"))
       eq(true, contains(dirs, "./README.md"))
       eq(true, contains(dirs, "./lua/say.lua"))
       eq(false, contains(dirs, "./lua/plenary/job.lua"))
@@ -122,7 +119,7 @@ describe("scandir", function()
       local dirs = scan.scan_dir(".", { respect_gitignore = true })
       vim.cmd ":silent !rm lua/test.so"
       eq("table", type(dirs))
-      eq(true, contains(dirs, "./CHANGELOG.md"))
+      eq(true, contains(dirs, "./README.md"))
       eq(true, contains(dirs, "./LICENSE"))
       eq(true, contains(dirs, "./lua/plenary/job.lua"))
       eq(false, contains(dirs, "./lua/test.so"))
@@ -225,7 +222,6 @@ describe("scandir", function()
     it("works for cwd", function()
       local dirs = scan.ls "."
       eq("table", type(dirs))
-      eq(true, contains_match(dirs, "CHANGELOG.md"))
       eq(true, contains_match(dirs, "LICENSE"))
       eq(true, contains_match(dirs, "README.md"))
       eq(true, contains_match(dirs, "lua"))
@@ -244,9 +240,8 @@ describe("scandir", function()
     it("works with opts.hidden for cwd", function()
       local dirs = scan.ls(".", { hidden = true })
       eq("table", type(dirs))
-      eq(true, contains_match(dirs, "CHANGELOG.md"))
-      eq(true, contains_match(dirs, "LICENSE"))
       eq(true, contains_match(dirs, "README.md"))
+      eq(true, contains_match(dirs, "LICENSE"))
       eq(true, contains_match(dirs, "lua"))
       eq(true, contains_match(dirs, "%.git$"))
     end)