Skip to content

Commit

Permalink
feat: display context for matches as documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mikavilpas committed Nov 5, 2024
1 parent e1ec348 commit b407004
Show file tree
Hide file tree
Showing 11 changed files with 274 additions and 35 deletions.
13 changes: 13 additions & 0 deletions .busted
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
return {
_all = {
coverage = false,
lpath = 'lua/?.lua;lua/?/init.lua',
lua = '~/.luarocks/bin/nlua',
},
default = {
verbose = true,
},
tests = {
verbose = true,
},
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ integration-tests/test-environment/.repro
integration-tests/test-environment/testdirs/
integration-tests/cypress/screenshots/
integration-tests/dist
.luarocks
lua_modules
luarocks
9 changes: 9 additions & 0 deletions .luarc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"runtime": {
"version": "LuaJIT",
"pathStrict": true
},
"type": {
"checkTableShape": true
}
}
24 changes: 24 additions & 0 deletions blink-cmp-rg.nvim-scm-1.rockspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---@diagnostic disable: lowercase-global
rockspec_format = "3.0"
package = "blink-cmp-rg.nvim"
version = "scm-1"
source = {
url = "git+https://github.com/mikavilpas/blink-cmp-rg.nvim",
}
dependencies = {
-- Add runtime dependencies here
-- e.g. "plenary.nvim",
-- blink is not available on luarocks (yet)
-- "blink.nvim",
}
test_dependencies = {
"nlua",
}
build = {
type = "builtin",
copy_directories = {
-- Add runtimepath directories, like
-- 'plugin', 'ftplugin', 'doc'
-- here. DO NOT add 'lua' or 'lib'.
},
}
48 changes: 48 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
set unstable := true

# allow `just --fmt`

COLOR_RESET := '\033[0m'
COLOR_GREEN := '\033[1;32m'
COLOR_BLUE_ := '\033[1;34m'
COLOR_YELLO := '\033[1;33m'
COLOR_WHITE := '\033[1;37m'

default: help

@help:
just --list

# Build the project
@build:
echo "Building project..."
luarocks init --no-gitignore
luarocks install busted 2.2.0-1

just help

# Check the code for lint errors
lint:
selene ./lua/ ./spec/

@if grep -r -e "#focus" --include \*.lua ./spec/; then \
echo "\n"; \
echo "Error: {{ COLOR_GREEN }}#focus{{ COLOR_RESET }} tags found in the codebase.\n"; \
echo "Please remove them to prevent issues with not accidentally running all tests."; \
exit 1; \
fi

# Run all tests
test:
luarocks test --local

# Run only the tests marked with #focus somewhere in the test name
test-focus:
luarocks test --local -- --filter=focus

# Reformat all code
format:
stylua lua/ spec/ integration-tests/

# Check the code for errors (lint + test + format)
check: lint test format
46 changes: 11 additions & 35 deletions lua/blink-cmp-rg/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,45 +54,21 @@ function RgSource:get_completions(context, resolve)
end

local lines = vim.split(result.stdout, "\n")
local cwd = vim.uv.cwd()
local cwd = vim.uv.cwd() or ""

local parsed = require("blink-cmp-rg.ripgrep_parser").parse(lines, cwd)

---@type table<string, blink.cmp.CompletionItem>
local items = {}
for _, line in ipairs(lines) do
local ok, item = pcall(vim.json.decode, line)
item = ok and item or {}

if item.type == "match" then
assert(
item.data.lines.text,
"ripgrep output missing item.data.lines.text"
)
assert(
item.data.path.text,
"ripgrep output missing item.data.path.text"
)
---@type string
local path = item.data.path.text
if path:sub(1, #cwd) == cwd then
path = path:sub(#cwd + 2)
end

---@type string[]
local documentation = {
item.data.lines.text,
" ", -- empty lines seem to do nothing, so just have something
path,
for _, file in pairs(parsed.files) do
for _, match in ipairs(file.submatches) do
---@diagnostic disable-next-line: missing-fields
items[match.match.text] = {
documentation = table.concat(file.lines, "\n"),
source_id = "blink-cmp-rg",
label = match.match.text .. " (rg)",
insertText = match.match.text,
}

for _, submatch in ipairs(item.data.submatches) do
---@diagnostic disable-next-line: missing-fields
items[submatch.match.text] = {
documentation = table.concat(documentation, "\n"),
source_id = "blink-cmp-rg",
label = submatch.match.text .. " (rg)",
insertText = submatch.match.text,
}
end
end
end

Expand Down
63 changes: 63 additions & 0 deletions lua/blink-cmp-rg/ripgrep_parser.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
local M = {}

---@class(exact) RipgrepOutput
---@field files table<string, RipgrepFile>

---@class RipgrepFile
---@field lines string[] the context preview for all the matches
---@field submatches RipgrepSubmatch[] the matches

---@class RipgrepSubmatch
---@field start number the start column of the match
---@field end_ number the end column of the match
---@field match {text: string} the matched text

---@param ripgrep_output string[] ripgrep output in jsonl format
---@param cwd string the current working directory
function M.parse(ripgrep_output, cwd)
---@type RipgrepOutput
local output = { files = {} }

for _, line in ipairs(ripgrep_output) do
local ok, json = pcall(vim.json.decode, line)
if ok then
if json.type == "begin" then
---@type string
local filename = json.data.path.text

output.files[filename] = { lines = {}, submatches = {} }
elseif json.type == "context" then
---@type string
local filename = json.data.path.text
local data = output.files[filename]

data.lines[#data.lines + 1] = json.data.lines.text
elseif json.type == "match" then
---@type string
local filename = json.data.path.text
local data = output.files[filename]

data.lines[#data.lines + 1] = json.data.lines.text

data.submatches[#data.submatches + 1] = {
start = json.data.submatches[1].start,
end_ = json.data.submatches[1]["end"],
match = { text = json.data.submatches[1].match.text },
}
elseif json.type == "end" then
---@type string
local filename = json.data.path.text
local data = output.files[filename]

if filename:sub(1, #cwd) == cwd then
filename = filename:sub(#cwd + 2)
end
data.lines[#data.lines + 1] = " "
data.lines[#data.lines + 1] = "> " .. filename
end
end
end
return output
end

return M
1 change: 1 addition & 0 deletions selene.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
std="vim"
22 changes: 22 additions & 0 deletions spec/blink-cmp-rg/rg-output.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{"type":"begin","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"}}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" //\n"},"line_number":13,"absolute_offset":462,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" // If the plugin works, this text should show up as a suggestion.\n"},"line_number":14,"absolute_offset":471,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" cy.typeIntoTerminal(\n"},"line_number":15,"absolute_offset":543,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" // NOTE: need to break it into parts so that this test file itself does\n"},"line_number":16,"absolute_offset":570,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" // not match the search :)\n"},"line_number":17,"absolute_offset":650,"submatches":[]}}
{"type":"match","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" \"hip\" + \"234\",\n"},"line_number":18,"absolute_offset":685,"submatches":[{"match":{"text":"234"},"start":17,"end":20}]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" )\n"},"line_number":19,"absolute_offset":708,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":"\n"},"line_number":20,"absolute_offset":716,"submatches":[]}}
{"type":"match","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" cy.contains(\"Hippopotamus\" + \"234 (rg)\")\n"},"line_number":21,"absolute_offset":717,"submatches":[{"match":{"text":"234"},"start":36,"end":39}]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":"\n"},"line_number":22,"absolute_offset":764,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" // should show documentation with more details about the match\n"},"line_number":23,"absolute_offset":765,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" //\n"},"line_number":24,"absolute_offset":834,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" // should show the text for the matched line\n"},"line_number":25,"absolute_offset":843,"submatches":[]}}
{"type":"match","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" cy.contains(\"Hippopotamus\" + \"234 was my previous password\")\n"},"line_number":26,"absolute_offset":894,"submatches":[{"match":{"text":"234"},"start":36,"end":39}]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" // should show the file name\n"},"line_number":27,"absolute_offset":961,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" cy.contains(dir.contents[\"other-file.txt\"].name)\n"},"line_number":28,"absolute_offset":996,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" })\n"},"line_number":29,"absolute_offset":1051,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":" })\n"},"line_number":30,"absolute_offset":1058,"submatches":[]}}
{"type":"context","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"lines":{"text":"})\n"},"line_number":31,"absolute_offset":1063,"submatches":[]}}
{"type":"end","data":{"path":{"text":"integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"},"binary_offset":null,"stats":{"elapsed":{"secs":0,"nanos":72959,"human":"0.000073s"},"searches":1,"searches_with_match":1,"bytes_searched":1066,"bytes_printed":4189,"matched_lines":3,"matches":3}}}
{"data":{"elapsed_total":{"human":"0.007127s","nanos":7126833,"secs":0},"stats":{"bytes_printed":4189,"bytes_searched":1066,"elapsed":{"human":"0.000073s","nanos":72959,"secs":0},"matched_lines":3,"matches":3,"searches":1,"searches_with_match":1}},"type":"summary"}
25 changes: 25 additions & 0 deletions spec/blink-cmp-rg/ripgrep_parser_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
local ripgrep_parser = require("blink-cmp-rg.ripgrep_parser")
local assert = require("luassert")

describe("ripgrep_parser", function()
local ripgrep_output_lines =
vim.fn.readfile("spec/blink-cmp-rg/rg-output.jsonl")

it("can parse according to the expected schema", function()
local result = ripgrep_parser.parse(ripgrep_output_lines, "/home/user")
local filename = "integration-tests/cypress/e2e/cmp-rg/basic_spec.cy.ts"

assert.is_not_nil(result.files)
assert.is_not_nil(result.files[filename])
assert.is_truthy(#result.files[filename].lines > 19)
assert.same(#result.files[filename].submatches, 3)

for _, submatch in ipairs(result.files[filename].submatches) do
assert.is_not_nil(submatch.start)
assert.is_not_nil(submatch.end_)
assert.is_not_nil(submatch.match.text)
end
end)

-- TODO test that the cwd is stripped from the filename
end)
55 changes: 55 additions & 0 deletions vim.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[selene]
base = "lua51"
name = "vim"

[vim]
any = true

[[describe.args]]
type = "string"
[[describe.args]]
type = "function"

[[it.args]]
type = "string"
[[it.args]]
type = "function"

[[before_each.args]]
type = "function"
[[after_each.args]]
type = "function"

[assert.is_not]
any = true

[assert.matches]
any = true

[assert.has_error]
any = true

[[assert.equals.args]]
type = "any"
[[assert.equals.args]]
type = "any"
[[assert.equals.args]]
type = "any"
required = false

[[assert.same.args]]
type = "any"
[[assert.same.args]]
type = "any"

[[assert.truthy.args]]
type = "any"

[[assert.falsy.args]]
type = "any"

[[assert.spy.args]]
type = "any"

[[assert.stub.args]]
type = "any"

0 comments on commit b407004

Please sign in to comment.