diff options
Diffstat (limited to 'modules/textadept')
-rw-r--r-- | modules/textadept/find.lua | 97 |
1 files changed, 42 insertions, 55 deletions
diff --git a/modules/textadept/find.lua b/modules/textadept/find.lua index 4b93d57f..68b43993 100644 --- a/modules/textadept/find.lua +++ b/modules/textadept/find.lua @@ -101,78 +101,73 @@ local escapes = { ['\\r'] = '\r', ['\\t'] = '\t', ['\\v'] = '\v', ['\\\\'] = '\\' } -local c = _SCINTILLA.constants - -- Finds and selects text in the current buffer. -- @param text The text to find. -- @param next Flag indicating whether or not the search direction is forward. -- @param flags Search flags. This is a number mask of 4 flags: match case (2), -- whole word (4), Lua pattern (8), and in files (16) joined with binary OR. -- If `nil`, this is determined based on the checkboxes in the find box. --- @param nowrap Flag indicating whether or not the search will not wrap. +-- @param no_wrap Flag indicating whether or not the search will not wrap. -- @param wrapped Utility flag indicating whether or not the search has wrapped -- for displaying useful statusbar information. This flag is used and set -- internally, and should not be set otherwise. -- @return position of the found text or `-1` -local function find_(text, next, flags, nowrap, wrapped) +local function find_(text, next, flags, no_wrap, wrapped) if text == '' then return end - local buffer = buffer - local first_visible_line = buffer.first_visible_line -- for 'no results found' - - local increment - if buffer.current_pos == buffer.anchor then - increment = 0 - elseif not wrapped then - increment = next and 1 or -1 - end - if not flags then + local c = _SCINTILLA.constants flags = 0 if M.match_case then flags = flags + c.SCFIND_MATCHCASE end if M.whole_word then flags = flags + c.SCFIND_WHOLEWORD end if M.lua then flags = flags + 8 end if M.in_files then flags = flags + 16 end end + if flags >= 16 then M.find_in_files() return end -- not performed here + local first_visible_line = buffer.first_visible_line -- for 'no results found' - local result - M.captures = nil + -- If text is selected, assume it is from the current search and increment the + -- caret appropriately for the next search. + if buffer:get_sel_text() ~= '' then + buffer:goto_pos(buffer[next and 'current_pos' or 'anchor'] + + (next and 1 or -1)) + end + local pos = -1 if flags < 8 then - buffer:goto_pos(buffer[next and 'current_pos' or 'anchor'] + increment) + -- Scintilla search. buffer:search_anchor() - result = buffer['search_'..(next and 'next' or 'prev')](buffer, flags, text) - buffer:scroll_range(buffer.anchor, buffer.current_pos) - elseif flags < 16 then -- lua pattern search (forward search only) - text = text:gsub('\\[abfnrtv\\]', escapes) - local buffer_text = buffer:get_text(buffer.length) - local results = {buffer_text:find(text, buffer.anchor + increment + 1)} - if #results > 0 then - M.captures = {table.unpack(results, 3)} - buffer:set_sel(results[2], results[1] - 1) + pos = buffer['search_'..(next and 'next' or 'prev')](buffer, flags, text) + elseif flags < 16 then + -- Lua pattern search. + local patt = text:gsub('\\[abfnrtv\\]', escapes) + local s = next and buffer.current_pos or 0 + local e = next and buffer.length or buffer.current_pos + local caps = {buffer:text_range(s, e):find(next and patt or '^.*()'..patt)} + M.captures = {table.unpack(caps, next and 3 or 4)} + if #caps > 0 then + pos, e = s + caps[next and 1 or 3] - 1, s + caps[2] + buffer:set_sel(e, pos) end - result = results[1] or -1 - else -- find in files - M.find_in_files() - return end + buffer:scroll_range(buffer.anchor, buffer.current_pos) - if result == -1 and not nowrap and not wrapped then -- wrap the search + -- If nothing was found, wrap the search. + if pos == -1 and not no_wrap then local anchor, pos = buffer.anchor, buffer.current_pos - buffer:goto_pos((next or flags >= 8) and 0 or buffer.length) + buffer:goto_pos(next and 0 or buffer.length) gui.statusbar_text = _L['Search wrapped'] events.emit(events.FIND_WRAPPED) - result = find_(text, next, flags, true, true) - if result == -1 then + pos = find_(text, next, flags, true, true) + if pos == -1 then gui.statusbar_text = _L['No results found'] - buffer:line_scroll(0, first_visible_line) + buffer:line_scroll(0, first_visible_line - buffer.first_visible_line) buffer:goto_pos(anchor) end - return result - elseif result ~= -1 and not wrapped then + elseif not wrapped then gui.statusbar_text = '' end - return result + return pos end events.connect(events.FIND, find_) @@ -188,7 +183,7 @@ local function find_incremental(text, next, anchor) M.incremental_start = buffer.current_pos + (next and 1 or -1) end buffer:goto_pos(M.incremental_start or 0) - find_(text, next, M.match_case and c.SCFIND_MATCHCASE or 0) + find_(text, next, M.match_case and _SCINTILLA.constants.SCFIND_MATCHCASE or 0) end --- @@ -300,7 +295,7 @@ local function replace(rtext) end events.connect(events.REPLACE, replace) -local MARK_FIND = _SCINTILLA.next_marker_number() +local INDIC_REPLACE = _SCINTILLA.next_indic_number() -- Replaces all found text. -- If any text is selected, all found text in that selection is replaced. -- This function ignores "Find in Files". @@ -310,7 +305,6 @@ local MARK_FIND = _SCINTILLA.next_marker_number() local function replace_all(ftext, rtext) if ftext == '' then return end if M.in_files then M.in_files = false end - local buffer = buffer buffer:begin_undo_action() local count = 0 if buffer:get_sel_text() == '' then @@ -320,26 +314,19 @@ local function replace_all(ftext, rtext) count = count + 1 end else - local anchor, current_pos = buffer.selection_start, buffer.selection_end - local s, e = anchor, current_pos - buffer:insert_text(e, '\n') - local end_marker = buffer:marker_add(buffer:line_from_position(e + 1), - MARK_FIND) + local s, e = buffer.selection_start, buffer.selection_end + buffer.indicator_current = INDIC_REPLACE + buffer:indicator_fill_range(e, 1) buffer:goto_pos(s) local pos = find_(ftext, true, nil, true) - while pos ~= -1 and - pos < buffer:position_from_line( - buffer:marker_line_from_handle(end_marker)) do + while pos ~= -1 and pos <= buffer:indicator_end(INDIC_REPLACE, s) do replace(rtext) count = count + 1 pos = find_(ftext, true, nil, true) end - e = buffer:position_from_line(buffer:marker_line_from_handle(end_marker)) - buffer:goto_pos(e) - buffer:delete_back() -- delete '\n' added - if s == current_pos then anchor = e - 1 else current_pos = e - 1 end - buffer:set_sel(anchor, current_pos) - buffer:marker_delete_handle(end_marker) + e = buffer:indicator_end(INDIC_REPLACE, s) + buffer:set_sel(s, e > 0 and e or buffer.length) + buffer:indicator_clear_range(e, 1) end gui.statusbar_text = ("%d %s"):format(count, _L['replacement(s) made']) buffer:end_undo_action() |