-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Search and replace across files with ripgrep
- Loading branch information
Showing
8 changed files
with
392 additions
and
278 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
local ts = vim.treesitter | ||
local uv = vim.uv or vim.loop | ||
|
||
---@class File | ||
---@field name string | ||
---@field content string | ||
---@field mtime { nsec: integer, sec: integer } | ||
---@field lang_tree LanguageTree | ||
local File = {} | ||
|
||
---@type table<string, File> | ||
local cache = {} | ||
|
||
---@param name string | ||
---@return File? | ||
function File.new(name) | ||
local fd = uv.fs_open(name, "r", 438) | ||
if not fd then | ||
return | ||
end | ||
local stat = uv.fs_fstat(fd) --[[@as uv.aliases.fs_stat_table]] | ||
local self = cache[name] | ||
if self and stat.mtime.sec == self.mtime.sec and stat.mtime.nsec == self.mtime.nsec then | ||
uv.fs_close(fd) | ||
return self | ||
end | ||
|
||
self = setmetatable({ name = name }, { __index = File }) | ||
self.mtime = stat.mtime | ||
self.content = uv.fs_read(fd, stat.size, 0) --[[@as string]] | ||
uv.fs_close(fd) | ||
if not name:match "%.ts$" then | ||
return | ||
end | ||
-- local ft = vim.filetype.match { filename = name } | ||
-- if not ft then | ||
-- return | ||
-- end | ||
local lang = ts.language.get_lang "typescript" | ||
if not lang then | ||
return | ||
end | ||
local has_parser, lang_tree = pcall(ts.get_string_parser, self.content, lang) | ||
if not has_parser then | ||
return | ||
end | ||
self.lang_tree = lang_tree | ||
self.lang_tree:parse() | ||
|
||
cache[name] = self | ||
return self | ||
end | ||
|
||
---@param regex string | ||
---@param on_file fun(file: File) | ||
---@param on_end fun() | ||
---@return nil | ||
function File.grep(regex, on_file, on_end) | ||
vim.system({ "rg", "--line-buffered", "--files-with-matches", regex }, { | ||
text = true, | ||
stdout = vim.schedule_wrap(function(err, files) | ||
if err then | ||
error(files) | ||
end | ||
if not files then | ||
on_end() | ||
return | ||
end | ||
for _, name in ipairs(vim.split(files, "\n", { plain = true })) do | ||
local file = File.new(name) | ||
if file then | ||
on_file(file) | ||
end | ||
end | ||
end), | ||
}, function(obj) | ||
if obj.code ~= 0 then | ||
error(obj.stderr) | ||
end | ||
end) | ||
end | ||
|
||
return File |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
---@class Range | ||
---@field start_row number | ||
---@field start_col number | ||
---@field end_row number | ||
---@field end_col number | ||
local Range = {} | ||
|
||
---@param node TSNode | ||
---@return Range | ||
function Range.from_node(node) | ||
local start_row, start_col, end_row, end_col = node:range() | ||
return setmetatable({ | ||
start_row = start_row, | ||
start_col = start_col, | ||
end_row = end_row, | ||
end_col = end_col, | ||
}, { __index = Range }) | ||
end | ||
|
||
---@param other Range | ||
---@return boolean | ||
function Range:before(other) | ||
return self.end_row < other.start_row or (self.end_row == other.start_row and self.end_col <= other.start_col) | ||
end | ||
|
||
---@param other Range | ||
---@return boolean | ||
function Range:inside(other) | ||
return ( | ||
(self.start_row > other.start_row or (self.start_row == other.start_row and self.start_col > other.start_col)) | ||
and (self.end_row < other.end_row or (self.end_row == other.end_row and self.end_col <= other.end_col)) | ||
) | ||
end | ||
|
||
return Range |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
local api = vim.api | ||
local ts = vim.treesitter | ||
local u = require "ssr.utils" | ||
|
||
local Replacer = {} | ||
|
||
--- Render template and replace one match. | ||
---@param buf buffer | ||
---@param match Match | ||
function Replacer:replace(buf, match) | ||
-- Render templates with captured nodes. | ||
local replace = self.template:gsub("()%$([_%a%d]+)", function(pos, var) | ||
local start_row, start_col, end_row, end_col = match.captures[var]:get() | ||
local lines = api.nvim_buf_get_text(buf, start_row, start_col, end_row, end_col, {}) | ||
u.remove_indent(lines, u.get_indent(buf, start_row)) | ||
local var_lines = vim.split(self.template:sub(1, pos), "\n") | ||
local var_line = var_lines[#var_lines] | ||
local template_indent = var_line:match "^%s*" | ||
u.add_indent(lines, template_indent) | ||
return table.concat(lines, "\n") | ||
end) | ||
replace = vim.split(replace, "\n") | ||
local start_row, start_col, end_row, end_col = match.range:get() | ||
u.add_indent(replace, u.get_indent(buf, start_row)) | ||
api.nvim_buf_set_text(buf, start_row, start_col, end_row, end_col, replace) | ||
end | ||
|
||
return Replacer |
Oops, something went wrong.