Re: [code] Sometimes replacing in textadept is too slow

From: Alexander Misel <alexander_misel.att.live.cn>
Date: Sat, 7 Sep 2019 05:11:54 +0000

Corrected for regex replacements
local function bg_find(text)
  if text == '' then return end
  return buffer:search_in_target(text)
end

local function replace_all(ftext, rtext)
  if ftext == '' then return end

  -- init flags
  local flags = 0
  if M.match_case then flags = flags + buffer.FIND_MATCHCASE end
  if M.whole_word then flags = flags + buffer.FIND_WHOLEWORD end
  local bg_replace
  if M.regex then
    flags = flags + buffer.FIND_REGEXP
    rtext = rtext:gsub('%f[\\]\\u(%x%x%x%x)', function(code)
      return utf8.char(tonumber(code, 16))
    end)
    bg_replace = function(rtext)
      return buffer:replace_target_re(rtext)
    end
  else
    bg_replace = function(rtext)
      return buffer:replace_target(rtext)
    end
  end
  buffer.search_flags = flags

  -- start replace action
  buffer:begin_undo_action()
  local count = 0
  if buffer.selection_empty then
    buffer:target_whole_document()
    local s = 0
    while bg_find(ftext) ~= -1 do
      s = s + bg_replace(rtext)
      count = count + 1
      buffer:set_target_range(s, buffer.length)
    end
  else
    local s, e = buffer.selection_start, buffer.selection_end
    buffer.indicator_current = INDIC_REPLACE
    buffer:indicator_fill_range(e, 1)
    local EOF = buffer.selection_end == buffer.length -- no indic at EOF
    buffer:set_target_range(s, e)
    local pos = bg_find(ftext)
    while pos ~= -1 and (EOF or pos < e) do
      if buffer.selection_empty then break end -- prevent infinite loops
      s = s + bg_replace(rtext)
      count = count + 1
      if EOF then
        buffer:set_target_range(s, buffer.length)
      else
        e = buffer:indicator_end(INDIC_REPLACE, s)
        buffer:set_target_range(s, e)
      end
      pos = bg_find(ftext)
    end
    e = buffer:indicator_end(INDIC_REPLACE, s)
    buffer:indicator_clear_range(e, 1)
  end
  ui.statusbar_text = string.format('%d %s', count, _L['replacement(s) made'])
  buffer:end_undo_action()
end
________________________________
From: Alexander Misel <alexander_misel.att.live.cn>
Sent: Friday, September 6, 2019 13:43
To: code.att.foicica.com <code.att.foicica.com>
Subject: Re: [code] Sometimes replacing in textadept is too slow

I forgot to remove
if buffer.selection_empty then break end -- prevent infinite loops
in else
________________________________
From: Alexander Misel <alexander_misel.att.live.cn>
Sent: Friday, September 6, 2019 13:36
To: code.att.foicica.com <code.att.foicica.com>
Subject: Re: [code] Sometimes replacing in textadept is too slow

I just worked out a slightly faster implementation that could finish replacing in a few seconds (it the long line is not wrapped). Maybe it could be improved.
local function bg_find(text)
  if text == '' then return end
  return buffer:search_in_target(text)
end

local function replace_all(ftext, rtext)
  if ftext == '' then return end

  -- init flags
  local flags = 0
  if M.match_case then flags = flags + buffer.FIND_MATCHCASE end
  if M.whole_word then flags = flags + buffer.FIND_WHOLEWORD end
  buffer.search_flags = flags
  local bg_replace
  if M.regex then
    flags = flags + buffer.FIND_REGEXP
    rtext = rtext:gsub('%f[\\]\\u(%x%x%x%x)', function(code)
      return utf8.char(tonumber(code, 16))
    end)
    bg_replace = function(rtext)
      return buffer:replace_target_re(rtext)
    end
  else
    bg_replace = function(rtext)
      return buffer:replace_target(rtext)
    end
  end

  -- start replace action
  buffer:begin_undo_action()
  local count = 0
  if buffer.selection_empty then
    buffer:target_whole_document()
    local s = 0
    while bg_find(ftext) ~= -1 do
      s = s + bg_replace(rtext)
      count = count + 1
      buffer:set_target_range(s, buffer.length)
    end
  else
    local s, e = buffer.selection_start, buffer.selection_end
    buffer.indicator_current = INDIC_REPLACE
    buffer:indicator_fill_range(e, 1)
    local EOF = buffer.selection_end == buffer.length -- no indic at EOF
    buffer:set_target_range(s, e)
    local pos = bg_find(ftext)
    while pos ~= -1 and (EOF or pos < e) do
      if buffer.selection_empty then break end -- prevent infinite loops
      s = s + bg_replace(rtext)
      count = count + 1
      if EOF then
        buffer:set_target_range(s, buffer.length)
      else
        e = buffer:indicator_end(INDIC_REPLACE, s)
        buffer:set_target_range(s, e)
      end
      pos = bg_find(ftext)
    end
    e = buffer:indicator_end(INDIC_REPLACE, s)
    buffer:indicator_clear_range(e, 1)
  end
  ui.statusbar_text = string.format('%d %s', count, _L['replacement(s) made'])
  buffer:end_undo_action()
end
________________________________
From: Mitchell <m.att.foicica.com>
Sent: Thursday, September 5, 2019 23:06
To: code.att.foicica.com <code.att.foicica.com>
Subject: Re: [code] Sometimes replacing in textadept is too slow

Hi,

On Thu, 5 Sep 2019, Alexander Misel wrote:

> I wanted to replace all occurences of a word in a single-line file (no line breaks), like raw JSON. When the word only occurs a few times, the speed is OK. But when it cames to a lot of occurences, it became slow and unresponsive. For example the attached file, replacing 'article' to 'art'.
>
> I also tried the terminal method
> sed -i s/article/art/g pop.txt
> and it finished within a second.
>
> So I wonder if it could speed up in Textadept.

When Textadept replaces text, it has to redraw the line, which includes calculating character positions. For long lines this will take a while, even if the lines are wrapped. Unfortunately, I don't see a way to accomplish this well. In this case, Textadept is not the proper tool for the job.

Cheers,
Mitchell

--
You are subscribed to code.att.foicica.com.
To change subscription settings, send an e-mail to code+help.att.foicica.com.
To unsubscribe, send an e-mail to code+unsubscribe.att.foicica.com.
-- 
You are subscribed to code.att.foicica.com.
To change subscription settings, send an e-mail to code+help.att.foicica.com.
To unsubscribe, send an e-mail to code+unsubscribe.att.foicica.com.
Received on Sat 07 Sep 2019 - 01:11:54 EDT

This archive was generated by hypermail 2.2.0 : Sat 07 Sep 2019 - 06:37:35 EDT