diff --git a/lua/symbols-outline/config.lua b/lua/symbols-outline/config.lua index fe2a45f..e61bd5e 100644 --- a/lua/symbols-outline/config.lua +++ b/lua/symbols-outline/config.lua @@ -55,6 +55,8 @@ M.defaults = { Event = { icon = '🗲', hl = 'TSType' }, Operator = { icon = '+', hl = 'TSOperator' }, TypeParameter = { icon = '𝙏', hl = 'TSParameter' }, + Component = { icon = '', hl = 'TSFunction' }, + Fragment = { icon = '', hl = 'TSConstant' }, }, } diff --git a/lua/symbols-outline/providers/init.lua b/lua/symbols-outline/providers/init.lua index 8f11389..f3228e5 100644 --- a/lua/symbols-outline/providers/init.lua +++ b/lua/symbols-outline/providers/init.lua @@ -1,6 +1,7 @@ local M = {} local providers = { + 'symbols-outline/providers/jsx', 'symbols-outline/providers/nvim-lsp', 'symbols-outline/providers/coc', 'symbols-outline/providers/markdown', diff --git a/lua/symbols-outline/providers/jsx.lua b/lua/symbols-outline/providers/jsx.lua new file mode 100644 index 0000000..626b6ae --- /dev/null +++ b/lua/symbols-outline/providers/jsx.lua @@ -0,0 +1,111 @@ +local M = {} + +local parsers = require("nvim-treesitter.parsers") + +local SYMBOL_COMPONENT = 27 +local SYMBOL_FRAGMENT = 28 + +function M.should_use_provider(bufnr) + local ft = vim.api.nvim_buf_get_option(bufnr, 'ft') + + return string.match(ft, 'typescriptreact') or string.match(ft, 'javascriptreact') +end + +function M.hover_info(_, _, on_info) + on_info(nil, { contents = { kind = 'nvim-lsp-jsx', contents = { 'No extra information availaible!' } } }) +end + +local function get_open_tag(node) + if node:type() == "jsx_element" then + for _, outer in ipairs(node:field("open_tag")) do + if outer:type() == "jsx_opening_element" then + return outer + end + end + end + + return nil +end + +local function jsx_node_detail(node, buf) + node = get_open_tag(node) or node + + local param_nodes = node:field("attribute") + if #param_nodes == 0 then return nil end + + local res = '{ ' .. table.concat(vim.tbl_map(function (el) + local a, b, c, d = el:range() + local text = vim.api.nvim_buf_get_text(buf, a, b, c, d, {}) + return text[1] + end, param_nodes), ' ') .. ' }' + + return res +end + +local function jsx_node_tagname(node, buf) + local tagnode = get_open_tag(node) or node + + local identifier = nil + + for _, val in ipairs(tagnode:field('name')) do + if val:type() == 'identifier' then + identifier = val + end + end + + if identifier then + local a, b, c, d = identifier:range() + local text = vim.api.nvim_buf_get_text(buf, a, b, c, d, {}) + local name = table.concat(text) + return name + end +end + +local function convert_ts(child, children, bufnr) + local is_frag = (child:type() == 'jsx_fragment') + + local a, b, c, d = child:range() + local range = { start = { line = a, character = b }, ['end'] = { line = c, character = d } } + + local converted = { + name = (not is_frag and (jsx_node_tagname(child, bufnr) or '')) or 'fragment', + children = (#children > 0 and children) or nil, + kind = (is_frag and SYMBOL_FRAGMENT) or SYMBOL_COMPONENT, + detail = jsx_node_detail(child, bufnr), + range = range, + selectionRange = range + } + + return converted +end + +local function parse_ts(root, children, bufnr) + children = children or {} + + for child in root:iter_children() do + if vim.tbl_contains({ 'jsx_element', 'jsx_self_closing_element' }, child:type()) then + local new_children = {} + + parse_ts(child, new_children, bufnr) + + table.insert(children, convert_ts(child, new_children, bufnr)) + else + parse_ts(child, children, bufnr) + end + end + + return children +end + +function M.request_symbols(on_symbols) + local bufnr = 0 + + local parser = parsers.get_parser(bufnr) + local root = parser:parse()[1]:root() + + local symbols = parse_ts(root, nil, bufnr) + -- local symbols = convert_ts(ctree) + on_symbols({ [1000000] = { result = symbols }}) +end + +return M diff --git a/lua/symbols-outline/symbols.lua b/lua/symbols-outline/symbols.lua index 33d17df..9778ce8 100644 --- a/lua/symbols-outline/symbols.lua +++ b/lua/symbols-outline/symbols.lua @@ -29,6 +29,8 @@ M.kinds = { 'Event', 'Operator', 'TypeParameter', + 'Component', + 'Fragment', } function M.icon_from_kind(kind)