Skip to content

Commit

Permalink
Merge pull request #1 from rxtsel/feat/refactor
Browse files Browse the repository at this point in the history
feat/refactor all code
  • Loading branch information
rxtsel authored Jul 7, 2024
2 parents fbb916c + 06a3e97 commit fc00138
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 115 deletions.
19 changes: 2 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ Install using your favorite package manager for Neovim. For example, using [lazy
event = "BufReadPost",
dependencies = {
"nvim-lua/plenary.nvim",
},
config = function()
require("template-string").setup()
end,
"nvim-treesitter/nvim-treesitter",
}
}
```

Expand All @@ -53,19 +51,6 @@ const props = {
<Test greeting={`Hello, ${props.name}!`} />;
```

## Configuration

The `setup` function accepts an optional configuration object with the following options:

- **jsx_brackets** `boolean | nil`: Enable/disable wrapping template literals with `{``}` inside JSX/TSX components. Defaults to `true` if not provided.

```lua
-- Default configuration
require('template-string').setup({
jsx_brackets = true, -- Wrap template literals with {``} inside JSX/TSX components
})
```

## License

This plugin is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
106 changes: 8 additions & 98 deletions lua/template-string.lua
Original file line number Diff line number Diff line change
@@ -1,108 +1,18 @@
---@class TemplateStringConfig
---@field jsx_brackets boolean | nil

local M = {}

local allowed_filetypes = {
javascript = true,
typescript = true,
javascriptreact = true,
typescriptreact = true,
}

local function is_allowed_filetype()
local filetype = vim.bo.filetype
return allowed_filetypes[filetype] or false
end

-- Function to wrap with {``} if inside a JSX/TSX component
local function wrap_with_brackets_if_necessary(content)
if content:find("%${") then
return "={`" .. content .. "`}"
else
return '="' .. content .. '"'
end
end

-- Function to replace quotes in the current line
local function replace_quotes_in_line()
if not is_allowed_filetype() then
return
end

local row = vim.api.nvim_win_get_cursor(0)[1]
local line = vim.api.nvim_buf_get_lines(0, row - 1, row, false)[1]

if not line then
return
end

local new_line = line

-- Replace quotes with backticks when ${ is found
new_line = new_line:gsub("(['\"])(.-)%${(.-)}(.-)%1", function(quote, before, inside, after)
return "`" .. before .. "${" .. inside .. "}" .. after .. "`"
end)

if M.jsx_brackets then
-- Wrap with {``} if inside a JSX/TSX component
new_line = new_line:gsub("=%s*`([^`]*)`", wrap_with_brackets_if_necessary)

-- Revert backticks to original quotes if ${ is not found
new_line = new_line:gsub("={[`{]+([^`]*)[`}]+}", function(content)
if not content:find("%${") then
-- Determine the original type of quotes, double or single
local original_quote = line:match("=[\"']") and '"' or line:match("=['\"]") and "'" or '"'
return "=" .. original_quote .. content .. original_quote
end
return "={" .. "`" .. content .. "`" .. "}"
end)
end

-- Also handle reverting solitary backticks on normal lines
new_line = new_line:gsub("`([^`]*)`", function(content)
if not content:find("%${") then
-- Determine the original type of quotes, double or single
local original_quote = line:match("[\"']") or '"'
return original_quote .. content .. original_quote
end
return "`" .. content .. "`"
end)

if new_line ~= line then
vim.api.nvim_buf_set_lines(0, row - 1, row, false, { new_line })
end
end

-- Function to execute update with debounce
local function debounce(fn, ms)
local timer = vim.loop.new_timer()
return function(...)
timer:stop()
local argv = { ... }
timer:start(
ms,
0,
vim.schedule_wrap(function()
fn(unpack(argv))
end)
)
end
end
local debounce = require("template-string.debounce")
local quotes = require("template-string.replace_quotes")

--- Configures the plugin behavior.
---@param opts TemplateStringConfig | nil Optional plugin configuration.
function M.setup(opts)
opts = opts or {}
-- Enable brackets for JSX/TSX
local jsx_brackets = opts.jsx_brackets == nil or opts.jsx_brackets
M.jsx_brackets = jsx_brackets
--- Configures the behavior of the plugin.
function M.setup()
-- Create a debounced version of the replace_quotes_in_line function
local debounced_replace = debounce.debounce(quotes.replace_quotes_in_line, 100)

-- Enable debounce
local debounced_replace = debounce(replace_quotes_in_line, 100)
-- Set up an autocmd to trigger the debounced function on TextChanged and TextChangedI events
vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
callback = debounced_replace,
})
end

--- @export
return M
20 changes: 20 additions & 0 deletions lua/template-string/allowed_filetypes.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
local vim = vim

local M = {}

-- List of allowed file types for syntax checking
local allowed_filetypes = {
javascript = true,
typescript = true,
javascriptreact = true,
typescriptreact = true,
}

--- Checks if the current buffer's file type is allowed for syntax checking.
-- @return boolean indicating if the file type is allowed.
function M.is_allowed_filetype()
local filetype = vim.bo.filetype
return allowed_filetypes[filetype] or false
end

return M
26 changes: 26 additions & 0 deletions lua/template-string/debounce.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
local vim = vim

local M = {}

--- Creates a debounced version of a function.
-- @param fn The function to debounce.
-- @param ms The debounce time in milliseconds.
-- @return The debounced function.
function M.debounce(fn, ms)
local timer = vim.loop.new_timer() -- Create a new timer from Vim's event loop

return function(...)
timer:stop() -- Stop the timer to reset debounce time
local argv = { ... } -- Capture arguments passed to the debounced function

timer:start(
ms,
0,
vim.schedule_wrap(function()
fn(unpack(argv)) -- Call the original function after debounce time
end)
)
end
end

return M
31 changes: 31 additions & 0 deletions lua/template-string/react_utils.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
local ts = require("nvim-treesitter.ts_utils")

local M = {}

--- Checks if the cursor is inside a React prop or JSX/TSX opening element.
-- @return boolean indicating if the cursor is inside a React prop or JSX/TSX opening element.
function M.is_inside_react_opening_element()
local node = ts.get_node_at_cursor()

if not node then
return false
end

-- Check if the node is a JSX/TSX string or template string
if node:type() == "string" or node:type() == "template_string" then
local prev_node = ts.get_previous_node(node)

if not prev_node then
return false
end

-- Check if the previous node is a property identifier
if prev_node:type() == "property_identifier" then
return true
end
end

return false
end

return M
56 changes: 56 additions & 0 deletions lua/template-string/replace_quotes.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
local filetypes = require("template-string.allowed_filetypes")
local u = require("template-string.react_utils")
local M = {}

--- Replaces quotes in a line based on the presence of template literals and context.
-- @param line The line of text to process.
-- @param use_brackets A boolean indicating if brackets should be used.
-- @return The processed line with appropriate quote replacements.
local function replace_quotes(line, use_brackets)
-- Replace quotes with backticks and brackets if ${} is found and use_brackets is true
line = line:gsub("(['\"])(.-)(%${.-})(.-)%1", function(quote, before, inside, after)
if use_brackets then
return "{`" .. before .. inside .. after .. "`}"
else
return "`" .. before .. inside .. after .. "`"
end
end)

-- Revert backticks and brackets to original quotes if ${} is not found in the content
line = line:gsub("{`([^`]*)`}", function(content)
if not content:find("%${.-}") then
local original_quote = line:match("[\"']") or '"'
return original_quote .. content .. original_quote
end
return "{`" .. content .. "`}"
end)

-- Revert solitary backticks to original quotes if ${} is not found in the content
line = line:gsub("`([^`]*)`", function(content)
if not content:find("%${.-}") then
local original_quote = line:match("[\"']") or '"'
return original_quote .. content .. original_quote
end
return "`" .. content .. "`"
end)

return line
end

--- Replaces quotes in the current line of the buffer if the filetype is allowed.
function M.replace_quotes_in_line()
if not filetypes.is_allowed_filetype() then
return
end

local row = vim.api.nvim_win_get_cursor(0)[1]
local line = vim.api.nvim_buf_get_lines(0, row - 1, row, false)[1]
local new_line = replace_quotes(line, u.is_inside_react_opening_element())

-- Update the buffer if there were changes
if new_line ~= line then
vim.api.nvim_buf_set_lines(0, row - 1, row, false, { new_line })
end
end

return M
7 changes: 7 additions & 0 deletions plugin/template-string.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
if exists('g:loaded_template_string')
finish
endif

lua require'template-string'.setup()

let g:loaded_template_string = 1

0 comments on commit fc00138

Please sign in to comment.