Compare commits
	
		
			No commits in common. "362d9e905d1cbb18f9c955d9e783b7813a90365d" and "87930bf3afe9e85e3ad588d4365463cb77348790" have entirely different histories.
		
	
	
		
			362d9e905d
			...
			87930bf3af
		
	
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,2 @@ | ||||
| /.lux/ | ||||
| lux.lock | ||||
| *.src.rock | ||||
|  | ||||
| @ -24,9 +24,7 @@ function Buffer.current() return Buffer.from_nr(0) end | ||||
| --- @param listed boolean | ||||
| --- @param scratch boolean | ||||
| --- @return u.Buffer | ||||
| function Buffer.create(listed, scratch) | ||||
|   return Buffer.from_nr(vim.api.nvim_create_buf(listed, scratch)) | ||||
| end | ||||
| function Buffer.create(listed, scratch) return Buffer.from_nr(vim.api.nvim_create_buf(listed, scratch)) end | ||||
| 
 | ||||
| function Buffer:set_tmp_options() | ||||
|   self:set_option('bufhidden', 'delete') | ||||
| @ -38,9 +36,7 @@ end | ||||
| function Buffer:get_option(nm) return vim.api.nvim_get_option_value(nm, { buf = self.bufnr }) end | ||||
| 
 | ||||
| --- @param nm string | ||||
| function Buffer:set_option(nm, val) | ||||
|   return vim.api.nvim_set_option_value(nm, val, { buf = self.bufnr }) | ||||
| end | ||||
| function Buffer:set_option(nm, val) return vim.api.nvim_set_option_value(nm, val, { buf = self.bufnr }) end | ||||
| 
 | ||||
| --- @param nm string | ||||
| function Buffer:get_var(nm) return vim.api.nvim_buf_get_var(self.bufnr, nm) end | ||||
| @ -71,11 +67,11 @@ end | ||||
| --- @param stop number 1-based line index | ||||
| function Buffer:lines(start, stop) return Range.from_lines(self.bufnr, start, stop) end | ||||
| 
 | ||||
| --- @param motion string | ||||
| --- @param txt_obj string | ||||
| --- @param opts? { contains_cursor?: boolean; pos?: u.Pos } | ||||
| function Buffer:motion(motion, opts) | ||||
| function Buffer:txtobj(txt_obj, opts) | ||||
|   opts = vim.tbl_extend('force', opts or {}, { bufnr = self.bufnr }) | ||||
|   return Range.from_motion(motion, opts) | ||||
|   return Range.from_motion(txt_obj, opts) | ||||
| end | ||||
| 
 | ||||
| --- @param event string|string[] | ||||
|  | ||||
| @ -1,9 +1,7 @@ | ||||
| local M = {} | ||||
| 
 | ||||
| --- @params name string | ||||
| function M.file_for_name(name) | ||||
|   return vim.fs.joinpath(vim.fn.stdpath 'cache', 'u.log', name .. '.log.jsonl') | ||||
| end | ||||
| function M.file_for_name(name) return vim.fs.joinpath(vim.fn.stdpath 'cache', 'u.log', name .. '.log.jsonl') end | ||||
| 
 | ||||
| -------------------------------------------------------------------------------- | ||||
| -- Logger class | ||||
| @ -32,10 +30,7 @@ end | ||||
| function Logger:write(level, ...) | ||||
|   local data = { ... } | ||||
|   if #data == 1 then data = data[1] end | ||||
|   (vim.uv or vim.loop).fs_write( | ||||
|     self.fd, | ||||
|     vim.json.encode { ts = os.date(), level = level, data = data } .. '\n' | ||||
|   ) | ||||
|   (vim.uv or vim.loop).fs_write(self.fd, vim.json.encode { ts = os.date(), level = level, data = data } .. '\n') | ||||
| end | ||||
| 
 | ||||
| function Logger:trace(...) self:write('INFO', ...) end | ||||
|  | ||||
| @ -2,9 +2,7 @@ local MAX_COL = vim.v.maxcol | ||||
| 
 | ||||
| --- @param bufnr number | ||||
| --- @param lnum number 1-based | ||||
| local function line_text(bufnr, lnum) | ||||
|   return vim.api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, false)[1] | ||||
| end | ||||
| local function line_text(bufnr, lnum) return vim.api.nvim_buf_get_lines(bufnr, lnum - 1, lnum, false)[1] end | ||||
| 
 | ||||
| --- @class u.Pos | ||||
| --- @field bufnr number buffer number | ||||
| @ -56,9 +54,7 @@ end | ||||
| 
 | ||||
| function Pos.__lt(a, b) return a.lnum < b.lnum or (a.lnum == b.lnum and a.col < b.col) end | ||||
| function Pos.__le(a, b) return a < b or a == b end | ||||
| function Pos.__eq(a, b) | ||||
|   return Pos.is(a) and Pos.is(b) and a.bufnr == b.bufnr and a.lnum == b.lnum and a.col == b.col | ||||
| end | ||||
| function Pos.__eq(a, b) return Pos.is(a) and Pos.is(b) and a.bufnr == b.bufnr and a.lnum == b.lnum and a.col == b.col end | ||||
| function Pos.__add(x, y) | ||||
|   if type(x) == 'number' then | ||||
|     x, y = y, x | ||||
| @ -81,7 +77,7 @@ function Pos.from_pos(name) | ||||
|   return Pos.new(p[1], p[2], p[3], p[4]) | ||||
| end | ||||
| 
 | ||||
| function Pos:is_invalid() return self.lnum == 0 and self.col == 0 and self.off == 0 end | ||||
| function Pos:is_invalid() return self.bufnr == 0 and self.lnum == 0 and self.col == 0 and self.off == 0 end | ||||
| 
 | ||||
| function Pos:clone() return Pos.new(self.bufnr, self.lnum, self.col, self.off) end | ||||
| 
 | ||||
| @ -206,9 +202,7 @@ end | ||||
| --- @return u.Pos|nil | ||||
| function Pos:find_match(max_chars, invocations) | ||||
|   if invocations == nil then invocations = {} end | ||||
|   if vim.tbl_contains(invocations, function(p) return self == p end, { predicate = true }) then | ||||
|     return nil | ||||
|   end | ||||
|   if vim.tbl_contains(invocations, function(p) return self == p end, { predicate = true }) then return nil end | ||||
|   table.insert(invocations, self) | ||||
| 
 | ||||
|   local openers = { '{', '[', '(', '<' } | ||||
| @ -218,10 +212,7 @@ function Pos:find_match(max_chars, invocations) | ||||
|   local is_closer = vim.tbl_contains(closers, c) | ||||
|   if not is_opener and not is_closer then return nil end | ||||
| 
 | ||||
|   local i, _ = vim | ||||
|     .iter(is_opener and openers or closers) | ||||
|     :enumerate() | ||||
|     :find(function(_, c2) return c == c2 end) | ||||
|   local i, _ = vim.iter(is_opener and openers or closers):enumerate():find(function(_, c2) return c == c2 end) | ||||
|   -- Store the character we will be looking for: | ||||
|   local c_match = (is_opener and closers or openers)[i] | ||||
| 
 | ||||
| @ -264,14 +255,7 @@ end | ||||
| --- @param lines string|string[] | ||||
| function Pos:insert_before(lines) | ||||
|   if type(lines) == 'string' then lines = vim.split(lines, '\n') end | ||||
|   vim.api.nvim_buf_set_text( | ||||
|     self.bufnr, | ||||
|     self.lnum - 1, | ||||
|     self.col - 1, | ||||
|     self.lnum - 1, | ||||
|     self.col - 1, | ||||
|     lines | ||||
|   ) | ||||
|   vim.api.nvim_buf_set_text(self.bufnr, self.lnum - 1, self.col - 1, self.lnum - 1, self.col - 1, lines) | ||||
| end | ||||
| 
 | ||||
| return Pos | ||||
|  | ||||
							
								
								
									
										106
									
								
								lua/u/range.lua
									
									
									
									
									
								
							
							
						
						
									
										106
									
								
								lua/u/range.lua
									
									
									
									
									
								
							| @ -37,13 +37,7 @@ function Range.new(start, stop, mode) | ||||
| 
 | ||||
|     local _1 = posstr(r.start) | ||||
|     local _2 = posstr(r.stop) | ||||
|     return string.format( | ||||
|       'Range{bufnr=%d, mode=%s, start=%s, stop=%s}', | ||||
|       r.start.bufnr, | ||||
|       r.mode, | ||||
|       _1, | ||||
|       _2 | ||||
|     ) | ||||
|     return string.format('Range{bufnr=%d, mode=%s, start=%s, stop=%s}', r.start.bufnr, r.mode, _1, _2) | ||||
|   end | ||||
|   setmetatable(r, { __index = Range, __tostring = str }) | ||||
|   return r | ||||
| @ -98,35 +92,35 @@ function Range.from_lines(bufnr, start_line, stop_line) | ||||
|   return Range.new(Pos.new(bufnr, start_line, 1), Pos.new(bufnr, stop_line, Pos.MAX_COL), 'V') | ||||
| end | ||||
| 
 | ||||
| --- @param motion string | ||||
| --- @param text_obj string | ||||
| --- @param opts? { bufnr?: number; contains_cursor?: boolean; pos?: u.Pos, user_defined?: boolean } | ||||
| --- @return u.Range|nil | ||||
| function Range.from_motion(motion, opts) | ||||
|   -- Options handling: | ||||
| function Range.from_motion(text_obj, opts) | ||||
|   opts = opts or {} | ||||
|   if opts.bufnr == nil then opts.bufnr = vim.api.nvim_get_current_buf() end | ||||
|   if opts.contains_cursor == nil then opts.contains_cursor = false end | ||||
|   if opts.user_defined == nil then opts.user_defined = false end | ||||
| 
 | ||||
|   -- Extract some information from the motion: | ||||
|   --- @type 'a'|'i', string | ||||
|   local scope, motion_rest = motion:sub(1, 1), motion:sub(2) | ||||
|   local is_txtobj = scope == 'a' or scope == 'i' | ||||
|   local is_quote_txtobj = is_txtobj and vim.tbl_contains({ "'", '"', '`' }, motion_rest) | ||||
|   --- @type "a" | "i" | ||||
|   local selection_type = text_obj:sub(1, 1) | ||||
|   local obj_type = text_obj:sub(#text_obj, #text_obj) | ||||
|   local is_quote = vim.tbl_contains({ "'", '"', '`' }, obj_type) | ||||
|   local cursor = Pos.from_pos '.' | ||||
| 
 | ||||
|   --- @type u.Pos | ||||
|   local start | ||||
|   --- @type u.Pos | ||||
|   local stop | ||||
|   -- Capture the original state of the buffer for restoration later. | ||||
|   local original_state = { | ||||
|     winview = vim.fn.winsaveview(), | ||||
|     regquote = vim.fn.getreg '"', | ||||
|     cursor = vim.fn.getpos '.', | ||||
|     pos_lbrack = vim.fn.getpos "'[", | ||||
|     pos_rbrack = vim.fn.getpos "']", | ||||
|   } | ||||
| 
 | ||||
|   vim.api.nvim_buf_call(opts.bufnr, function() | ||||
|     local original_state = { | ||||
|       winview = vim.fn.winsaveview(), | ||||
|       regquote = vim.fn.getreg '"', | ||||
|       posdot = vim.fn.getpos '.', | ||||
|       poslb = vim.fn.getpos "'[", | ||||
|       posrb = vim.fn.getpos "']", | ||||
|     } | ||||
| 
 | ||||
|     if opts.pos ~= nil then opts.pos:save_to_pos '.' end | ||||
| 
 | ||||
|     Pos.invalid():save_to_pos "'[" | ||||
| @ -137,44 +131,39 @@ function Range.from_motion(motion, opts) | ||||
|     vim.cmd { | ||||
|       cmd = 'normal', | ||||
|       bang = not opts.user_defined, | ||||
|       args = { '""y' .. motion }, | ||||
|       args = { '""y' .. text_obj }, | ||||
|       mods = { silent = true }, | ||||
|     } | ||||
|     on_yank_enabled = prev_on_yank_enabled | ||||
| 
 | ||||
|     start = Pos.from_pos "'[" | ||||
|     stop = Pos.from_pos "']" | ||||
| 
 | ||||
|     -- Restore original state: | ||||
|     vim.fn.winrestview(original_state.winview) | ||||
|     vim.fn.setreg('"', original_state.regquote) | ||||
|     vim.fn.setpos('.', original_state.posdot) | ||||
|     vim.fn.setpos("'[", original_state.poslb) | ||||
|     vim.fn.setpos("']", original_state.posrb) | ||||
| 
 | ||||
|     if | ||||
|       -- I have no idea why, but when yanking `i"`, the stop-mark is | ||||
|       -- placed on the ending quote. For other text-objects, the stop- | ||||
|       -- mark is placed before the closing character. | ||||
|       (is_quote and selection_type == 'i' and stop:char() == obj_type) | ||||
|       -- *Sigh*, this also sometimes happens for `it` as well. | ||||
|       or (text_obj == 'it' and stop:char() == '<') | ||||
|     then | ||||
|       stop = stop:next(-1) or stop | ||||
|     end | ||||
|   end) | ||||
|   -- Restore original state: | ||||
|   vim.fn.winrestview(original_state.winview) | ||||
|   vim.fn.setreg('"', original_state.regquote) | ||||
|   vim.fn.setpos('.', original_state.cursor) | ||||
|   vim.fn.setpos("'[", original_state.pos_lbrack) | ||||
|   vim.fn.setpos("']", original_state.pos_rbrack) | ||||
| 
 | ||||
|   if start == stop and start:is_invalid() then return nil end | ||||
|   if opts.contains_cursor and not Range.new(start, stop):contains(cursor) then return nil end | ||||
| 
 | ||||
|   -- Fixup the bounds: | ||||
|   if | ||||
|     -- I have no idea why, but when yanking `i"`, the stop-mark is | ||||
|     -- placed on the ending quote. For other text-objects, the stop- | ||||
|     -- mark is placed before the closing character. | ||||
|     (is_quote_txtobj and scope == 'i' and stop:char() == motion_rest) | ||||
|     -- *Sigh*, this also sometimes happens for `it` as well. | ||||
|     or (motion == 'it' and stop:char() == '<') | ||||
|   then | ||||
|     stop = stop:next(-1) or stop | ||||
|   end | ||||
|   if is_quote_txtobj and scope == 'a' then | ||||
|     start = start:find_next(1, motion_rest) or start | ||||
|     stop = stop:find_next(-1, motion_rest) or stop | ||||
|   end | ||||
| 
 | ||||
|   if | ||||
|     opts.contains_cursor | ||||
|     and not Range.new(start, stop):contains(Pos.new(unpack(original_state.cursor))) | ||||
|   then | ||||
|     return nil | ||||
|   if is_quote and selection_type == 'a' then | ||||
|     start = start:find_next(1, obj_type) or start | ||||
|     stop = stop:find_next(-1, obj_type) or stop | ||||
|   end | ||||
| 
 | ||||
|   return Range.new(start, stop) | ||||
| @ -255,9 +244,7 @@ function Range.smallest(ranges) | ||||
|   return smallest | ||||
| end | ||||
| 
 | ||||
| function Range:clone() | ||||
|   return Range.new(self.start:clone(), self.stop ~= nil and self.stop:clone() or nil, self.mode) | ||||
| end | ||||
| function Range:clone() return Range.new(self.start:clone(), self.stop ~= nil and self.stop:clone() or nil, self.mode) end | ||||
| function Range:line_count() | ||||
|   if self:is_empty() then return 0 end | ||||
|   return self.stop.lnum - self.start.lnum + 1 | ||||
| @ -321,8 +308,7 @@ function Range:line(l) | ||||
|   if l < 0 then l = self:line_count() + l + 1 end | ||||
|   if l > self:line_count() then return end | ||||
| 
 | ||||
|   local line_indices = | ||||
|     vim.fn.getregionpos(self.start:as_vim(), self.stop:as_vim(), { type = self.mode }) | ||||
|   local line_indices = vim.fn.getregionpos(self.start:as_vim(), self.stop:as_vim(), { type = self.mode }) | ||||
|   local line_bounds = line_indices[l] | ||||
| 
 | ||||
|   local start = Pos.new(unpack(line_bounds[1])) | ||||
| @ -341,9 +327,7 @@ function Range:replace(replacement) | ||||
|   local function update_stop_non_linewise() | ||||
|     local new_last_line_num = self.start.lnum + #replacement - 1 | ||||
|     local new_last_col = #(replacement[#replacement] or '') | ||||
|     if new_last_line_num == self.start.lnum then | ||||
|       new_last_col = new_last_col + self.start.col - 1 | ||||
|     end | ||||
|     if new_last_line_num == self.start.lnum then new_last_col = new_last_col + self.start.col - 1 end | ||||
|     self.stop = Pos.new(bufnr, new_last_line_num, new_last_col) | ||||
|   end | ||||
|   local function update_stop_linewise() | ||||
| @ -413,9 +397,7 @@ end | ||||
| --- @param amount number | ||||
| function Range:must_shrink(amount) | ||||
|   local shrunk = self:shrink(amount) | ||||
|   if shrunk == nil or shrunk:is_empty() then | ||||
|     error 'error in Range:must_shrink: Range:shrink() returned nil' | ||||
|   end | ||||
|   if shrunk == nil or shrunk:is_empty() then error 'error in Range:must_shrink: Range:shrink() returned nil' end | ||||
|   return shrunk | ||||
| end | ||||
| 
 | ||||
|  | ||||
| @ -218,8 +218,7 @@ function Renderer:_reconcile() -- {{{ | ||||
|       self:_set_lines(lnum0, lnum0, true, { line_change.item }) | ||||
|     elseif line_change.kind == 'change' then | ||||
|       -- Compute inter-line diff, and apply: | ||||
|       local col_changes = | ||||
|         H.levenshtein(vim.split(line_change.from, ''), vim.split(line_change.to, '')) | ||||
|       local col_changes = H.levenshtein(vim.split(line_change.from, ''), vim.split(line_change.to, '')) | ||||
| 
 | ||||
|       for _, col_change in ipairs(col_changes) do | ||||
|         local cnum0 = col_change.index - 1 | ||||
| @ -311,15 +310,7 @@ function Renderer:get_pos_infos(pos0) -- {{{ | ||||
|   -- because the NeoVim API is over-inclusive in what it returns: | ||||
|   --- @type RendererExtmark[] | ||||
|   local intersecting_extmarks = vim | ||||
|     .iter( | ||||
|       vim.api.nvim_buf_get_extmarks( | ||||
|         self.bufnr, | ||||
|         self.ns, | ||||
|         pos0, | ||||
|         pos0, | ||||
|         { details = true, overlap = true } | ||||
|       ) | ||||
|     ) | ||||
|     .iter(vim.api.nvim_buf_get_extmarks(self.bufnr, self.ns, pos0, pos0, { details = true, overlap = true })) | ||||
|     --- @return RendererExtmark | ||||
|     :map(function(ext) | ||||
|       --- @type number, number, number, { end_row?: number; end_col?: number }|nil | ||||
|  | ||||
| @ -37,10 +37,7 @@ function Signal:set(value) | ||||
|   -- We don't handle cyclic updates: | ||||
|   if self.changing then | ||||
|     if M.debug then | ||||
|       vim.notify( | ||||
|         'circular dependency detected' .. (self.name and (' in ' .. self.name) or ''), | ||||
|         vim.log.levels.WARN | ||||
|       ) | ||||
|       vim.notify('circular dependency detected' .. (self.name and (' in ' .. self.name) or ''), vim.log.levels.WARN) | ||||
|     end | ||||
|     return | ||||
|   end | ||||
| @ -146,10 +143,7 @@ function Signal:debounce(ms) | ||||
|     local now_ms = (vim.uv or vim.loop).hrtime() / 1e6 | ||||
| 
 | ||||
|     -- If there is anything older than `ms` in our queue, emit it: | ||||
|     local older_than_ms = vim | ||||
|       .iter(state.queued) | ||||
|       :filter(function(item) return now_ms - item.ts > ms end) | ||||
|       :totable() | ||||
|     local older_than_ms = vim.iter(state.queued):filter(function(item) return now_ms - item.ts > ms end):totable() | ||||
|     local last_older_than_ms = older_than_ms[#older_than_ms] | ||||
|     if last_older_than_ms then | ||||
|       filtered:set(last_older_than_ms.value) | ||||
|  | ||||
							
								
								
									
										2
									
								
								lux.toml
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								lux.toml
									
									
									
									
									
								
							| @ -1,5 +1,5 @@ | ||||
| package = "u.nvim" | ||||
| version = "0.2.0" | ||||
| version = "0.1.0" | ||||
| lua = ">=5.1" | ||||
| 
 | ||||
| [description] | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| call_parentheses = "None" | ||||
| collapse_simple_statement = "Always" | ||||
| column_width = 100 | ||||
| column_width = 120 | ||||
| indent_type = "Spaces" | ||||
| indent_width = 2 | ||||
| quote_style = "AutoPreferSingle" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user