diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5533048..661dcea 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -41,5 +41,21 @@ if-statement spans multiple lines. A pull request for supporting a new language requires: 1. Adding `queries/[LANG]/context.scm` as explained in the previous section. -2. Adding `test/test.[LANG EXT]` with code examples the `context.scm` is designed to support. + +2. Adding `test/lang/test.[LANG]` or `test/lang/test.[LANG].[EXT]` with code examples the `context.scm` is designed to support. + - These test files use custom comment directives to annotate what lines should be a context. It has the format. + + ```c + // {{TEST}} -- mark start of test + + int main() { // {{CONTEXT}} -- mark line as a context + + + // {{CURSOR}} -- where cursor needs to be for contexts to be shown. + + } + ``` + + See `test/lang/test.c` for examples. + 3. Updating `README.md` to mark `[LANG]` as supported. diff --git a/test/lang/test.bash b/test/lang/test.bash index f71ee42..4b6714e 100644 --- a/test/lang/test.bash +++ b/test/lang/test.bash @@ -1,96 +1,79 @@ #!/bin/bash -foo() { - if [ 1 -eq 1 ]; then +# {{TEST}} + +foo() { # {{CONTEXT}} + + if [ 1 -eq 1 ]; then # {{CONTEXT}} echo 1 - - - - - - + # {{CURSOR}} fi - case "$i" in - 1) echo 1 - - - - +} + + +# {{TEST}} + +bar() { # {{CONTEXT}} + case "$i" in # {{CONTEXT}} + 1) echo 1 # {{CONTEXT}} + # {{CURSOR}} ;; 2|3) echo 2 or 3 ;; *) echo default ;; esac - - - while [ $x -le 5 ] - do - echo "Welcome $x times" - - - - - - x=$(( $x + 1 )) - done - - # until is also a while loop - until [ $x -gt 5 ] - do - echo Counter: $x - - - - - - - ((x++)) - done - - # select is a for statement - select character in Sheldon Leonard Penny Howard Raj - do - echo "Selected character: $character" - - - - - - echo "Selected number: $REPLY" - done - - for ((i=0; i<=10000; i++)); do - - - - - - - - echo "$i" - done - - } +# {{TEST}} + +baz() { # {{CONTEXT}} + while [ $x -le 5 ] # {{CONTEXT}} + do + echo "Welcome $x times" + + x=$(( $x + 1 )) + # {{CURSOR}} + done +} + +# {{TEST}} + +baz2() { # {{CONTEXT}} + # until is also a while loop + until [ $x -gt 5 ] # {{CONTEXT}} + do + echo Counter: $x + ((x++)) + # {{CURSOR}} + done +} + +# {{TEST}} + +# select is a for statement +select character in Sheldon Leonard Penny Howard Raj # {{CONTEXT}} +do + echo "Selected character: $character" + + # {{CURSOR}} +done + +# {{POPCONTEXT}} + +for ((i=0; i<=10000; i++)); do # {{CONTEXT}} - - - - - - - - + # {{CURSOR}} + echo "$i" +done diff --git a/test/lang/test.c b/test/lang/test.c index 3bf0036..cb3e365 100644 --- a/test/lang/test.c +++ b/test/lang/test.c @@ -1,148 +1,90 @@ -struct Bert { +// {{TEST}} + +struct Bert { // {{CONTEXT}} int *f1; - // comment int *f2; - // comment - // comment - // comment - // comment - // comment + + // {{CURSOR}} }; -typedef enum { + +// {{TEST}} + +typedef enum { // {{CONTEXT}} E1, E2, E3 - // comment - // comment - // comment - // comment - // comment - // comment + // {{CURSOR}} } Myenum; -int main(int arg1, + +// {{TEST}} + +int main(int arg1, // {{CONTEXT}} char **arg2, - char **arg3 - ) + char **arg3) { - if (arg1 == 4 + if (arg1 == 4 // {{CONTEXT}} && arg2 == arg3) { - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - for (int i = 0; i < arg1; i++) { - // comment - // comment - // comment - // comment - while (1) { - // comment - // comment - // comment - // comment - // comment + // {{CURSOR}} + + for (int i = 0; i < arg1; i++) { // {{CONTEXT}} + + // {{CURSOR}} + while (1) { // {{CONTEXT}} + + + // {{CURSOR}} } - do { - // comment - // comment - // comment - // comment - // comment - - } while (1); - // comment - // comment - // comment - // comment - // comment } - - } else if (arg1 == 4) { - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - - } else { - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - } +} - switch (arg1) { - // comment + +// {{TEST}} + +void foo(int a) { // {{CONTEXT}} + if (a) { // {{CONTEXT}} + do { // {{CONTEXT}} + + + + // {{CURSOR}} + } while (1); + } +} + + +// {{TEST}} + +void bar(int a) { // {{CONTEXT}} + if (a) { // {{CONTEXT}} + + } else if (a == 4) { // {{CONTEXT}} // comment + } else { // {{CONTEXT}} + + + + // {{CURSOR}} + } +} + + +// {{TEST}} + +void baz(int a) { // {{CONTEXT}} + switch (a) { // {{CONTEXT}} case 0: - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment break; - case 1: { - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment - // comment + case 1: { // {{CONTEXT}} + + + + // {{CURSOR}} } break; } } diff --git a/test/lang/test.lua b/test/lang/test.lua new file mode 100644 index 0000000..80e0257 --- /dev/null +++ b/test/lang/test.lua @@ -0,0 +1,13 @@ +-- {{TEST}} + +local function foo() -- {{CONTEXT}} + + local function bar() -- {{CONTEXT}} + + + + -- {{CURSOR}} + + end + +end diff --git a/test/test.c b/test/test.c new file mode 100644 index 0000000..3bf0036 --- /dev/null +++ b/test/test.c @@ -0,0 +1,148 @@ +struct Bert { + int *f1; + // comment + int *f2; + // comment + // comment + // comment + // comment + // comment +}; + +typedef enum { + E1, + E2, + E3 + // comment + // comment + // comment + // comment + // comment + // comment +} Myenum; + +int main(int arg1, + char **arg2, + char **arg3 + ) +{ + + if (arg1 == 4 + && arg2 == arg3) { + + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + for (int i = 0; i < arg1; i++) { + // comment + // comment + // comment + // comment + while (1) { + // comment + // comment + // comment + // comment + // comment + } + + do { + // comment + // comment + // comment + // comment + // comment + + } while (1); + // comment + // comment + // comment + // comment + // comment + } + + } else if (arg1 == 4) { + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + + } else { + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + + } + + switch (arg1) { + // comment + // comment + case 0: + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + break; + case 1: { + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + // comment + } break; + } +} diff --git a/test/lang/test_file.lua b/test/test_file.lua similarity index 100% rename from test/lang/test_file.lua rename to test/test_file.lua diff --git a/test/ts_context_spec.lua b/test/ts_context_spec.lua index 021e2ea..47f0dfc 100644 --- a/test/ts_context_spec.lua +++ b/test/ts_context_spec.lua @@ -5,6 +5,7 @@ local clear = helpers.clear local exec_lua = helpers.exec_lua local cmd = helpers.api.nvim_command local feed = helpers.feed +local api = helpers.api local function install_langs(langs) if type(langs) == 'string' then @@ -22,7 +23,52 @@ local function install_langs(langs) ]], langs) end -local function get_langs() +---@param line string +---@return string? +local function parse_directive(line) + --- @type string? + local directive = line:match('{{([A-Z]+)}}') + return directive +end + +--- @param filename string +--- @return table? contexts +local function parse_directives(filename) + local f = io.open(filename, 'r') + if not f then + return + end + + local context = {} --- @type table + local contexts = {} --- @type table + + local i = 0 + for l in f:lines() do + local directive = parse_directive(l) + if directive then + if directive == 'TEST' then + context = {} + elseif directive == 'CURSOR' then + contexts[i] = vim.deepcopy(context) + elseif directive == 'CONTEXT' then + table.insert(context, i) + elseif directive == 'POPCONTEXT' then + table.remove(context, #context) + end + end + i = i + 1 + end + f:close() + + for _, c in pairs(contexts) do + table.sort(c) + end + + return contexts +end + +local langs = {} --- @type string[] +do local f = assert(io.open('README.md', 'r')) local readme_langs = {} --- @type table for l in f:lines() do @@ -35,18 +81,16 @@ local function get_langs() f:close() f = assert(io.open('nvim-treesitter/lockfile.json', 'r')) - local txt = f:read('*a') - local j = vim.json.decode(txt) - local langs = {} --- @type string[] - for k in pairs(j) do + for k in pairs(vim.json.decode(f:read('*a'))) do if readme_langs[k] then langs[#langs+1] = k readme_langs[k] = nil end end - print('Invalid languages:', table.concat(vim.tbl_keys(readme_langs), ', ')) - return langs + if next(readme_langs) then + print('Invalid languages:', table.concat(vim.tbl_keys(readme_langs), ', ')) + end end describe('ts_context', function() @@ -91,7 +135,7 @@ describe('ts_context', function() it('edit a file', function() install_langs('lua') exec_lua[[require'treesitter-context'.setup{}]] - cmd('edit test/lang/test_file.lua') + cmd('edit test/test_file.lua') exec_lua [[vim.treesitter.start()]] feed'' feed'jj' @@ -141,7 +185,7 @@ describe('ts_context', function() f:close() end) - for _, lang in ipairs(get_langs()) do + for _, lang in ipairs(langs) do it(lang, function() install_langs(lang) @@ -182,6 +226,51 @@ describe('ts_context', function() end) + describe('contexts:', function() + for _, lang in ipairs(langs) do + it(lang, function() + install_langs(lang) + + local test_file = 'test/lang/test.'..lang + if not vim.uv.fs_stat(test_file) then + pending('No test file') + return + end + + local contexts = parse_directives(test_file) + + if not contexts or not next(contexts) then + pending('No tests') + return + end + + cmd('edit '..test_file) + + for cursor_row, context_rows in pairs(contexts) do + local bufnr = api.nvim_get_current_buf() + local winid = api.nvim_get_current_win() + api.nvim_win_set_cursor(winid, {cursor_row + 1, 0}) + assert(helpers.fn.getline('.'):match('{{CURSOR}}')) + feed(string.format('zt%d', #context_rows + 2)) + + --- @type [integer,integer,integer,integer][] + local ranges = exec_lua([[ + return require('treesitter-context.context').get(...) + ]], bufnr, winid) + + local act_context_rows = {} --- @type integer[] + for _, r in ipairs(ranges) do + table.insert(act_context_rows, r[1]) + end + + helpers.eq(context_rows, act_context_rows, string.format('test for cursor %d failed', cursor_row)) + end + + end) + end + + end) + describe('language:', function() before_each(function() exec_lua[[require'treesitter-context'.setup{ @@ -240,7 +329,7 @@ describe('ts_context', function() it('c', function() install_langs('c') - cmd('edit test/lang/test.c') + cmd('edit test/test.c') exec_lua [[vim.treesitter.start()]] feed''