From 8e5e5ecc650d06225069d37a059ff965d278356f Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Wed, 10 Apr 2024 09:06:31 +0300 Subject: [PATCH] feat(ecma): jsdoc --- .../languages/ecmascript/defaults.lua | 5 ++ .../languages/ecmascript/functions.lua | 28 +++++++++++ lua/splitjoin/languages/jsdoc/defaults.lua | 16 +++++++ lua/splitjoin/languages/jsdoc/functions.lua | 42 +++++++++++++++++ lua/splitjoin/util/node.lua | 5 +- lua/splitjoin/util/options.lua | 1 + lua/splitjoin/util/string.lua | 8 ++++ queries/javascript/splitjoin.scm | 2 + queries/jsdoc/splitjoin.scm | 1 + test/fixtures/fixture.js | 12 +++++ test/helpers.lua | 27 ++++++----- test/init.lua | 1 + test/javascript_spec.lua | 46 +++++++++++++++++++ test/lua_spec.lua | 6 +-- test/run.sh | 2 +- 15 files changed, 183 insertions(+), 19 deletions(-) create mode 100644 lua/splitjoin/languages/jsdoc/defaults.lua create mode 100644 lua/splitjoin/languages/jsdoc/functions.lua create mode 100644 queries/jsdoc/splitjoin.scm diff --git a/lua/splitjoin/languages/ecmascript/defaults.lua b/lua/splitjoin/languages/ecmascript/defaults.lua index 4c4d6b7..860b639 100644 --- a/lua/splitjoin/languages/ecmascript/defaults.lua +++ b/lua/splitjoin/languages/ecmascript/defaults.lua @@ -62,6 +62,11 @@ return { join = ECMAScript.join_arrow_function, }, + -- comment = { + -- split = ECMAScript.split_comment, + -- join = ECMAScript.join_comment, + -- } + }, } diff --git a/lua/splitjoin/languages/ecmascript/functions.lua b/lua/splitjoin/languages/ecmascript/functions.lua index 00882fd..a8fb17c 100644 --- a/lua/splitjoin/languages/ecmascript/functions.lua +++ b/lua/splitjoin/languages/ecmascript/functions.lua @@ -98,4 +98,32 @@ function ECMAScript.join_arrow_function(node, options) Node.goto_node(node) end +-- function ECMAScript.split_comment(node, options) +-- local text = Node.get_text(node) +-- if String.is_multiline(text) or vim.startwith(text, '//') then return end +-- local indent = options.default_indent or ' ' +-- local append, get = String.append('') +-- append( +-- '/**\n', +-- indent, +-- '* ', +-- text.gsub([[(^/**)|(*/$)]], '') +-- '\n */' +-- ) +-- Node.replace(node, get()) +-- Node.trim_line_end(node) +-- Node.trim_line_end(node, 1) +-- Node.goto_node(node) +-- end +-- +-- function ECMAScript.join_comment(node, options) +-- local text = Node.get_text(node) +-- if String.is_multiline(text) or vim.startwith(text, '//') then return end +-- local row, col = node:range() +-- local comment = vim.treesitter.get_node{ pos = { row, col - 1 } } +-- local description = text.gsub([[(^/**)|(*/$)]], ''); +-- Node.replace(comment, '/** ' .. description .. ' */') +-- Node.goto_node(comment) +-- end + return ECMAScript diff --git a/lua/splitjoin/languages/jsdoc/defaults.lua b/lua/splitjoin/languages/jsdoc/defaults.lua new file mode 100644 index 0000000..8dab990 --- /dev/null +++ b/lua/splitjoin/languages/jsdoc/defaults.lua @@ -0,0 +1,16 @@ +local JSDoc = require'splitjoin.languages.jsdoc.functions' + +---@type SplitjoinLanguageConfig +return { + + nodes = { + + description = { + split = JSDoc.split_jsdoc_description, + join = JSDoc.join_jsdoc_description, + trailing_separator = false, + }, + + }, + +} diff --git a/lua/splitjoin/languages/jsdoc/functions.lua b/lua/splitjoin/languages/jsdoc/functions.lua new file mode 100644 index 0000000..568937c --- /dev/null +++ b/lua/splitjoin/languages/jsdoc/functions.lua @@ -0,0 +1,42 @@ +local Node = require'splitjoin.util.node' +local String = require'splitjoin.util.string' + +local JSDoc = {} + +function JSDoc.split_jsdoc_description(node, options) + local text = Node.get_text(node) + if String.is_multiline(text) then return end + text = text:gsub([[%*$]], '') + local indent = options.default_indent or ' ' + local base_indent = Node.get_base_indent(node) + local append, get = String.append('') + append( + '\n', + indent, + base_indent, + '* ', + text, + '\n', + ' *' + ) + local row, col = unpack(vim.api.nvim_win_get_cursor(0)); + Node.replace(node, get()) + Node.trim_line_end(node) + Node.trim_line_end(node, 1) + vim.api.nvim_win_set_cursor(0, { row + 1, col - 1 }) +end + +function JSDoc.join_jsdoc_description(node, options) + local text = Node.get_text(node) + if String.is_multiline(text) then return end + local nrow, ncol = node:range() + local comment = vim.treesitter.get_node { pos = { nrow, ncol - 1 } } + if comment and not String.is_singleline(Node.get_text(comment)) then + local row, col = unpack(vim.api.nvim_win_get_cursor(0)); + Node.replace(comment, '/** ' .. text .. ' */') + Node.goto_node(comment) + vim.api.nvim_win_set_cursor(0, { row - 1, col + 1 }) + end +end + +return JSDoc diff --git a/lua/splitjoin/util/node.lua b/lua/splitjoin/util/node.lua index 55f7df3..6ed98bb 100644 --- a/lua/splitjoin/util/node.lua +++ b/lua/splitjoin/util/node.lua @@ -112,8 +112,9 @@ function Node.get_base_indent(node) end ---@param node TSNode -function Node.trim_line_end(node) - local row = node:range() +function Node.trim_line_end(node, rowoffset) + local noderow = node:range() + local row = noderow + (rowoffset or 0) local trimmed = Buffer.get_line(0, row):gsub('%s*$', '') vim.api.nvim_buf_set_lines(0, row, diff --git a/lua/splitjoin/util/options.lua b/lua/splitjoin/util/options.lua index 956df89..4781737 100644 --- a/lua/splitjoin/util/options.lua +++ b/lua/splitjoin/util/options.lua @@ -18,6 +18,7 @@ local function get_defaults() ecmascript = require'splitjoin.languages.ecmascript.defaults', javascript = require'splitjoin.languages.javascript.defaults', typescript = require'splitjoin.languages.typescript.defaults', + jsdoc = require'splitjoin.languages.jsdoc.defaults', json = require'splitjoin.languages.json.defaults', html = require'splitjoin.languages.html.defaults', css = require'splitjoin.languages.css.defaults', diff --git a/lua/splitjoin/util/string.lua b/lua/splitjoin/util/string.lua index e44570f..312338f 100644 --- a/lua/splitjoin/util/string.lua +++ b/lua/splitjoin/util/string.lua @@ -7,6 +7,14 @@ function String.is_lengthy(str) return #str > 0 end +function String.is_multiline(str) + return #vim.split(vim.fn.trim(str), '\n') > 1 +end + +function String.is_singleline(str) + return #vim.split(vim.fn.trim(str), '\n') == 1 +end + function String.split(str, sep, opts) opts = vim.tbl_extend('keep', opts or {}, { plain = true, trimempty = true }) return vim.split(str, sep, opts) diff --git a/queries/javascript/splitjoin.scm b/queries/javascript/splitjoin.scm index 71049a2..aefa86d 100644 --- a/queries/javascript/splitjoin.scm +++ b/queries/javascript/splitjoin.scm @@ -15,3 +15,5 @@ ; assignment patterns (array_pattern) @splitjoin.javascript.array (object_pattern) @splitjoin.javascript.object + +(comment) @splitjoin.javascript.comment diff --git a/queries/jsdoc/splitjoin.scm b/queries/jsdoc/splitjoin.scm new file mode 100644 index 0000000..e807a60 --- /dev/null +++ b/queries/jsdoc/splitjoin.scm @@ -0,0 +1 @@ +(description) @splitjoin.jsdoc.description diff --git a/test/fixtures/fixture.js b/test/fixtures/fixture.js index 31178d4..698f27a 100644 --- a/test/fixtures/fixture.js +++ b/test/fixtures/fixture.js @@ -23,3 +23,15 @@ const g = () => 0 function destruct({ a, b, c }, d) { return { a, b, c, d }; } destruct = ({ a, b, c }, d) => 0; + + /** jsdoc */ + const jsdoc = (thing) => thing + +/** + * multiline + * jsdoc + */ +const multilineJsdoc = (thing) => thing + +/** jsdoc @param {number} thing */ +const paramJsdoc = (thing) => thing diff --git a/test/helpers.lua b/test/helpers.lua index 70e2c57..9cd64e6 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -34,6 +34,11 @@ function M.get_char_at_cursor() return char end +---@param lang string language name +---@param name string suite name +---@param input string code to operate on +---@param expected string expected result +---@param go_to string|number[] go_to result function M.make_suite(lang, name, input, expected, go_to) local assert = require 'luassert' local splitjoin = require'splitjoin' @@ -43,19 +48,19 @@ function M.make_suite(lang, name, input, expected, go_to) local bufnr local function create () - if not bufnr then - bufnr = vim.api.nvim_create_buf(true, false) - vim.api.nvim_win_set_buf(0, bufnr) - vim.opt.filetype = lang - local lines = vim.split(input, '\n', { plain = true, trimempty = false }) - vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) - if type(go_to) == 'string' then - vim.fn.search(go_to) - elseif type(go_to) == 'table' then - vim.api.nvim_win_set_cursor(0, go_to) + if not bufnr then + bufnr = vim.api.nvim_create_buf(true, false) + vim.api.nvim_win_set_buf(0, bufnr) + vim.opt.filetype = lang + local lines = vim.split(input, '\n', { plain = true, trimempty = false }) + vim.api.nvim_buf_set_lines(bufnr, 0, 1, false, lines) + if type(go_to) == 'string' then + vim.fn.search(go_to) + elseif type(go_to) == 'table' then + vim.api.nvim_win_set_cursor(0, go_to) + end end end - end local function destroy() vim.api.nvim_buf_delete(bufnr, { force = true }) diff --git a/test/init.lua b/test/init.lua index 60e7319..9489fe0 100644 --- a/test/init.lua +++ b/test/init.lua @@ -26,6 +26,7 @@ function M.setup() 'lua', 'css', 'json', + 'jsdoc', 'javascript', 'typescript', 'html', diff --git a/test/javascript_spec.lua b/test/javascript_spec.lua index da6d976..aa7de5a 100644 --- a/test/javascript_spec.lua +++ b/test/javascript_spec.lua @@ -313,6 +313,52 @@ describe(lang, function() ) end) + describe('jsdoc', function() + H.make_suite(lang, 'single line jsdoc', + d[[ + /** jsdoc */ + const x = y => y + ]], + d[[ + /** + * jsdoc + */ + const x = y => y + ]], + 'jsdoc' + ) + H.make_suite(lang, 'indented jsdoc', + d[[ + /** indented jsdoc */ + const x = y => y + ]], + d[[ + /** + * indented jsdoc + */ + const x = y => y + ]], + 'jsdoc' + ) + H.make_suite(lang, 'multiline jsdoc', + d[[ + /** + * multiline + * jsdoc + */ + const x = y => y + ]], + d[[ + /** + * multiline + * jsdoc + */ + const x = y => y + ]], + 'jsdoc' + ) + end) + describe('const f = function() { return 0; }', function() H.make_suite(lang, '', d[[ diff --git a/test/lua_spec.lua b/test/lua_spec.lua index 7a71ca8..5358211 100644 --- a/test/lua_spec.lua +++ b/test/lua_spec.lua @@ -211,11 +211,7 @@ describe(lang, function() end) H.make_suite(lang, 'params', d[[ - local function call( - a, - b, - c - ) end + local function call(a, b, c) end ]], d[[ local function call( diff --git a/test/run.sh b/test/run.sh index 65c5779..053c461 100755 --- a/test/run.sh +++ b/test/run.sh @@ -11,7 +11,7 @@ set -o errexit -o pipefail -o noclobber -o nounset # -allow a command to fail with !’s side effect on errexit # -use return value from ${PIPESTATUS[0]}, because ! hosed $? -! getopt --test > /dev/null +! getopt --test > /dev/null if [[ ${PIPESTATUS[0]} -ne 4 ]]; then echo 'I’m sorry, `getopt --test` failed in this environment.' exit 1