Skip to content

Commit

Permalink
feat: add linemagic and cellcontent queries
Browse files Browse the repository at this point in the history
  • Loading branch information
AbaoFromCUG committed Jan 14, 2025
1 parent 2d19b0b commit d18755d
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 91 deletions.
2 changes: 2 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#!/usr/bin/env sh

make test
make document
pnpm lint-staged
pnpm run test
1 change: 0 additions & 1 deletion .neoconf.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"mode": "direct",
"remote_address": "127.0.0.1:9103",
"highlight": {
"mode": "separator",
"enable": true
}
}
Expand Down
71 changes: 41 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ local default_config = {
---@type neopyter.TextObjectOption # ref `:h neopyter.TextObjectOption`
textobject = {
enable = true,
queries = { "cellseparator" },
-- more capture, poorer performance
queries = { "cellseparator", "cellcontent", "cell" },
},
---@type neopyter.InjectionOption # ref `:h neopyter.InjectionOption`
injection = {
Expand Down Expand Up @@ -344,40 +345,40 @@ require("blink-cmp").setup({

## textobjects

Supported captures in `textobjects` query group
Neopyter load `textobjects.scm` dynamic according `config.textobject.queries`:

- `@cell`
- `@cell.code`
- `@cell.magic`
- `@cell.markdown`
- `@cell.raw`
- `@cellseparator`
- `@cellseparator.code`
- `@cellseparator.magic`
- `@cellseparator.markdown`
- `@cellseparator.raw`
- `@cellbody`
- `@cellbody.code`
- `@cellbody.magic`
- `@cellbody.markdown`
- `@cellbody.raw`
- `@cellcontent`
- `@cellcontent.code`
- `@cellcontent.magic`
- `@cellcontent.markdown`
- `@cellcontent.raw`
- `@cellborder`
- `@cellborder.start`
- `@cellborder.start.markdown`
- `@cellborder.start.raw`
- `@cellborder.end`
- `@cellborder.end.markdown`
- `@cellborder.end.raw`
- `@linemagic`
```lua
{
"SUSTech-data/neopyter",
---@type neopyter.Option
opts = {
textobject = {
enable = true,
queries = {
"linemagic",
"cellseparator",
"cellcontent",
"cell"
},
},
},
}
```

The more queries you added, the poorer performance to capture, so only add what you need.
Then you can config you `nvim-treesitter-textobjects` as usually:

```lua
require'nvim-treesitter.configs'.setup {
textobjects = {
select = {
enable = true,
lookahead = true,
keymaps = {
["aj"] = { query = "@cell", desc = "Select cell" },
["ij"] = { query = "@cellcontent", desc = "Select cell content" },
},
},
move = {
enable = true,
goto_next_start = {
Expand All @@ -392,6 +393,16 @@ require'nvim-treesitter.configs'.setup {

```

Supported queries:

- `@linemagic`
- `@cellseparator`
- `@cellseparator.code`
- `@cellseparator.markdown`
- `@cellseparator.raw`
- `@cellcontent`
- `@cell`

# API

`Neopyter` provides rich lua APIs, you could use below code as initialization:
Expand Down
73 changes: 42 additions & 31 deletions doc/neopyter.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*neopyter.txt* For Last change: 2025 January 13
*neopyter.txt* For Last change: 2025 January 14

==============================================================================
Table of Contents *neopyter-table-of-contents*
Expand Down Expand Up @@ -148,7 +148,8 @@ Default configuration ~
---@type neopyter.TextObjectOption # ref `:h neopyter.TextObjectOption`
textobject = {
enable = true,
queries = { "cellseparator" },
-- more capture, poorer performance
queries = { "cellseparator", "cellcontent", "cell" },
},
---@type neopyter.InjectionOption # ref `:h neopyter.InjectionOption`
injection = {
Expand Down Expand Up @@ -321,40 +322,40 @@ BLINK.CMP *neopyter-integration-blink.cmp*

TEXTOBJECTS *neopyter-integration-textobjects*

Supported captures in `textobjects` query group
Neopyter load `textobjects.scm` dynamic according `config.textobject.queries`:

- `@cell`
- `@cell.code`
- `@cell.magic`
- `@cell.markdown`
- `@cell.raw`
- `@cellseparator`
- `@cellseparator.code`
- `@cellseparator.magic`
- `@cellseparator.markdown`
- `@cellseparator.raw`
- `@cellbody`
- `@cellbody.code`
- `@cellbody.magic`
- `@cellbody.markdown`
- `@cellbody.raw`
- `@cellcontent`
- `@cellcontent.code`
- `@cellcontent.magic`
- `@cellcontent.markdown`
- `@cellcontent.raw`
- `@cellborder`
- `@cellborder.start`
- `@cellborder.start.markdown`
- `@cellborder.start.raw`
- `@cellborder.end`
- `@cellborder.end.markdown`
- `@cellborder.end.raw`
- `@linemagic`
>lua
{
"SUSTech-data/neopyter",
---@type neopyter.Option
opts = {
textobject = {
enable = true,
queries = {
"linemagic",
"cellseparator",
"cellcontent",
"cell"
},
},
},
}
<

The more queries you added, the poorer performance to capture, so only add what
you need. Then you can config you `nvim-treesitter-textobjects` as usually:

>lua
require'nvim-treesitter.configs'.setup {
textobjects = {
select = {
enable = true,
lookahead = true,
keymaps = {
["aj"] = { query = "@cell", desc = "Select cell" },
["ij"] = { query = "@cellcontent", desc = "Select cell content" },
},
},
move = {
enable = true,
goto_next_start = {
Expand All @@ -368,6 +369,16 @@ Supported captures in `textobjects` query group
}
<

Supported queries:

- `@linemagic`
- `@cellseparator`
- `@cellseparator.code`
- `@cellseparator.markdown`
- `@cellseparator.raw`
- `@cellcontent`
- `@cell`


==============================================================================
7. API *neopyter-api*
Expand Down
18 changes: 16 additions & 2 deletions lua-tests/neopyter/parser/percent_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ describe("parse percent", function()
)
end)
end)
describe("line magic", function()
---@type neopyter.PercentParser
local parser
before_each(function()
parser = PercentParser:new({
trim_whitespace = false,
})
end)

it("register", function()
local ret = vim.iter(vim.treesitter.query.list_predicates()):find("match-line-magic?")
assert.not_nil(ret)
end)
end)

describe("cells parse", function()
---@type neopyter.PercentParser
Expand Down Expand Up @@ -309,13 +323,13 @@ describe("cells parse", function()
}, cells)
assert.equal("%%coo\nimport foo", parser:parse_source(code, cells[1]))
end)
it("multiple lines cell", function()
it("multiple lines cell", function()
local code = common.load_buffer({
"# %%",
"# %%coo",
"import foo",
"",
"# bar"
"# bar",
})
local cells = parser:parse_notebook(code).cells
assert.are.same({
Expand Down
19 changes: 0 additions & 19 deletions lua-tests/neopyter/utils_spec.lua

This file was deleted.

3 changes: 2 additions & 1 deletion lua/neopyter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ local default_config = {
---@type neopyter.TextObjectOption # ref `:h neopyter.TextObjectOption`
textobject = {
enable = true,
queries = { "cellseparator" },
-- more capture, poorer performance
queries = { "cellseparator", "cellcontent", "cell" },
},
---@type neopyter.InjectionOption # ref `:h neopyter.InjectionOption`
injection = {
Expand Down
23 changes: 22 additions & 1 deletion lua/neopyter/parser/percent.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function PercentParser:new(opt)
)
]]
)

vim.treesitter.query.add_predicate("match-line-magic?", PercentParser.match_line_magic, { force = true, all = true })
vim.treesitter.query.add_predicate("match-percent-separator?", PercentParser.match_percent_separator, { force = true, all = true })
vim.treesitter.query.add_predicate("match-cell-content?", PercentParser.match_cell_content, { force = true, all = true })
vim.treesitter.query.add_directive("set-percent-metadata!", PercentParser.set_percent_metadata, { force = true, all = true })
Expand Down Expand Up @@ -89,6 +89,27 @@ function PercentParser.parse_percent(line)
return "code", vim.trim(line:sub(6))
end

--- match line magic
---@param match table<integer, TSNode[]>
---@param pattern integer
---@param source integer|string
---@param predicate any[]
---@return boolean?
function PercentParser.match_line_magic(match, pattern, source, predicate)
local cap = match[predicate[2]]
local node = type(cap) == "table" and cap[1] or cap
if not node then
return false
end
local _, start_col = node:start()
if start_col ~= 0 then
return false
end

local line = vim.treesitter.get_node_text(node, source)
return not not line:match("# %%%w+")
end

--- (all) match cell separator
---@param match table<integer, TSNode[]>
---@param pattern integer
Expand Down
51 changes: 45 additions & 6 deletions res/queries/python/textobjects/cell.scm
Original file line number Diff line number Diff line change
@@ -1,13 +1,52 @@
;; inherits: python
;; extends

; vanilla script, without separator
(module
(comment) @cellseparator
(_) @_noncellseparator
(comment) @cellseparator
(#not-match-percent-separator? @_noncellseparator)
(#match-percent-separator? @cellseparator)
)
.
(_) @_nonseparator @_start @_end
.
(_)* @_nonseparator @_end
.
(#match-cell-content? @_nonseparator)
(#make-range! "cell" @_start @_end)
)

; first cell, follow a separator
(module
.
(_) @_nonseparator @_start @_end
.
(_)* @_nonseparator @_end
.
(comment) @_cellseparator
(#match-cell-content? @_nonseparator)
(#match-percent-separator? @_cellseparator)
(#make-range! "cell" @_start @_end)
)

; cell between two separator
(module
(comment) @_cellseparator @_start
.
(_)+ @_nonseparator @_end
.
(comment) @_cellseparator
(#match-cell-content? @_nonseparator)
(#match-percent-separator? @_cellseparator)
(#make-range! "cell" @_start @_end)
)


; latest cell after separator
(module
(comment) @_cellseparator @_start
.
(_) @_nonseparator @_end
(_)* @_nonseparator @_end
.
(#match-cell-content? @_nonseparator)
(#match-percent-separator? @_cellseparator)
(#make-range! "cell" @_start @_end)
)

Loading

0 comments on commit d18755d

Please sign in to comment.