<commit_before># frozen_string_literal: true

module Textbringer
  module Commands
    GLOBAL_MAP.define_key("\e.", :find_tag)

    CTAGS = {
      path: nil,
      tags: nil
    }

    define_command(:find_tag) do
      path = File.expand_path("tags")
      if CTAGS[:path] != path
        CTAGS[:path] = path
        tags = Hash.new { |h, k| h[k] = [] }
        File.read(path).scan(/^(.*?)\t(.*?)\t(.*?)(?:;".*)?$/) do
          |name, file, addr|
          tags[name].push([file, addr])
        end
        CTAGS[:tags] = tags
        message("Loaded #{path}")
      else
        tags = CTAGS[:tags]
      end
      buffer = Buffer.current
      name = buffer.save_excursion {
        buffer.backward_word(regexp: /[A-Za-z_\-]/)
        if buffer.looking_at?(/[A-Za-z_\-]+/)
          match_string(0)
        else
          nil
        end
      }
      if name.nil?
        raise EditorError, "No name found at point"
      end
      candidates = tags[name]
      if candidates.empty?
        raise EditorError, "Tag not found: #{name}"
      end
      file, addr = candidates.first
      find_file(file)
      case addr
      when /\A\d+\z/
        goto_line(addr.to_i)
      when %r'\A/\^(.*)\$/\z'
        beginning_of_buffer        
        re_search_forward("^" + Regexp.quote($1) + "$")
      else
        raise EditorError, "Invalid address: #{addr}"
      end
      Window.current.recenter_if_needed
    end
  end
end
<commit_msg>Add a prefix argument to find_tag.<commit_after># frozen_string_literal: true

module Textbringer
  module Commands
    GLOBAL_MAP.define_key("\e.", :find_tag)

    CTAGS = {
      path: nil,
      tags: nil,
      name: nil,
      candidates: nil,
      index: nil
    }

    define_command(:find_tag) do |next_p = current_prefix_arg|
      prev_file = nil
      tags = get_tags
      if next_p
        name = CTAGS[:name]
        if name.nil?
          raise EditorError, "Tag search not started yet"
        end
        candidates = CTAGS[:candidates]
        index = CTAGS[:index]
        prev_file, = candidates[index]
        if next_p == :-
          index -= 1
        else
          index += 1
        end
        if index < 0
          raise EditorError, "No previous tags for #{name}"
        end
        if index >= candidates.size
          raise EditorError, "No more tags for #{name}"
        end
      else
        buffer = Buffer.current
        name = buffer.save_excursion {
          buffer.backward_word(regexp: /[A-Za-z_\-]/)
          if buffer.looking_at?(/[A-Za-z_\-]+/)
            match_string(0)
          else
            nil
          end
        }
        if name.nil?
          raise EditorError, "No name found at point"
        end
        candidates = tags[name]
        if candidates.empty?
          raise EditorError, "Tag not found: #{name}"
        end
        CTAGS[:name] = name
        CTAGS[:candidates] = candidates
        CTAGS[:index] = index = 0
      end
      file, addr = candidates[index]
      find_file(file)
      case addr
      when /\A\d+\z/
        goto_line(addr.to_i)
      when %r'\A/\^(.*)\$/\z'
        if file == prev_file
          if next_p == :-
            beginning_of_line
          else
            end_of_line
          end
        else
          beginning_of_buffer
        end
        re = "^" + Regexp.quote($1) + "$"
        if next_p == :-
          re_search_backward(re)
        else
          re_search_forward(re)
        end
        beginning_of_line
      else
        raise EditorError, "Invalid address: #{addr}"
      end
      Window.current.recenter_if_needed
    end

    def get_tags
      path = File.expand_path("tags")
      if CTAGS[:path] != path
        CTAGS[:path] = path
        tags = Hash.new { |h, k| h[k] = [] }
        File.read(path).scan(/^(.*?)\t(.*?)\t(.*?)(?:;".*)?$/) do
          |name, file, addr|
          tags[name].push([file, addr])
        end
        CTAGS[:tags] = tags
        message("Loaded #{path}")
      end
      CTAGS[:tags]
    end
  end
end

{'fraction_non_alphanumeric': 0.1277390438247012, 'fraction_numerical': 0.00199203187250996, 'mean_word_length': 1.6016839378238341, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4533292', 'n_tokens_mistral': 1318, 'n_tokens_neox': 1296, 'n_words': 299}