class Milkode::SearchContents

Constants

COL_LIMIT
DEFAULT_WIDE_MATCH_RANGE
DISP_NUM
FILTER_BY_DIRECTORIES_FILES
FILTER_BY_PACKAGE_NUM
FILTER_BY_SUFFIX_NUM
LIMIT_NUM
MATH_FILE_DISP
MATH_FILE_LIMIT
MatchRecord
NTH

Attributes

page[R]
total_records[R]

Public Class Methods

new(path, params, query, suburl, locale) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 32
def initialize(path, params, query, suburl, locale)
  @path             = path
  @params           = params
  @q                = query
  @page             = params[:page].to_i || 0
  @offset           = params[:offset].to_i
  @line             = params[:line].to_i
  @is_onematch      = params[:onematch]  == 'on'
  @is_sensitive     = params[:sensitive] == 'on'
  @suburl           = suburl
  @homeurl          = @suburl + "/home/"
  @locale           = locale

  @searcher_fuzzy_gotoline = nil

  # 検索1 : クエリーそのまま
  @records, @total_records, result = Database.instance.search(@q.keywords, @q.multi_match_keywords, @q.packages, path, @q.fpaths, @q.suffixs, @q.fpath_or_packages, @offset, LIMIT_NUM)
  grep_contents(@q.keywords, @q.wide_match_range)

  # 検索2 : マッチしなかった時におすすめクエリーがある場合

  # gotolineモード (test_cdstk.rb:55)
  if @match_records.empty? && recommended_fuzzy_gotoline?
    # 専用の Searcher を作成
    @searcher_fuzzy_gotoline = SearchFuzzyGotoLine.new(@path, @params, @q, @suburl)

    # 結果をコピーする
    @total_records = @searcher_fuzzy_gotoline.total_records
    @match_records = @searcher_fuzzy_gotoline.match_records
    @next_index    = @searcher_fuzzy_gotoline.next_index
    @end_index     = @searcher_fuzzy_gotoline.end_index
    @next_line     = nil
  end

  # ワイド検索範囲
  if @match_records.empty? && recommended_wide_match_range?
    grep_contents(@q.keywords, DEFAULT_WIDE_MATCH_RANGE)

    # 検索範囲0の自動マッチは混乱をまねくのでやめる
    # if @match_records.empty?
    #   grep_contents(@q.keywords, 0)
    # end
  end

  # 先頭をファイル名とみなす自動マッチは混乱をまねくのでやめる
  # if @match_records.empty? && recommended_fpath_or_packages?
  #   # おすすめクエリーに変換
  #   q2 = @q.conv_head_keyword_to_fpath_or_packages
    
  #   # 検索
  #   @records, @total_records = Database.instance.search(q2.keywords, q2.multi_match_keywords, q2.packages, path, q2.fpaths, q2.suffixs, q2.fpath_or_packages, @offset, LIMIT_NUM)
    
  #   # 再grep
  #   grep_contents(q2.keywords, q2.wide_match_range)
  # end
  
  # 検索3 : マッチするファイル
  @match_files = []
  if @offset == 0 && @line == 0
    t = 0

    if (@path != "")
      @match_files, t = Database.instance.search([], @q.multi_match_keywords, @q.packages, path, @q.fpaths + @q.keywords, @q.suffixs, @q.fpath_or_packages, @offset, MATH_FILE_LIMIT)
    else
      @match_files, t = Database.instance.search([], @q.multi_match_keywords, @q.packages, path, @q.fpaths, @q.suffixs, @q.fpath_or_packages + @q.keywords, @offset, MATH_FILE_LIMIT)
    end
  end

  # Search4 : Drilldown
  begin 
    @drilldown_packages    = DocumentTable.drilldown(result, "package", FILTER_BY_PACKAGE_NUM)
    @drilldown_directories = make_drilldown_directories(result)
    @drilldown_suffixs     = DocumentTable.drilldown(result, "suffix", FILTER_BY_SUFFIX_NUM)
  rescue Groonga::InvalidArgument
    @drilldown_packages = @drilldown_directories = @drilldown_suffixs = []
  end
end

Public Instance Methods

data_range() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 139
def data_range
  @offset..(@offset + @end_index)
end
directjump?() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 280
def directjump?
  @searcher_fuzzy_gotoline && @searcher_fuzzy_gotoline.directjump?
end
directjump_url() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 284
def directjump_url
  @searcher_fuzzy_gotoline.directjump_url
end
html_contents() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 143
    def html_contents
      match_groups = @match_records.reduce([]) do |g, m|
        if (g.empty?)
          g << [m]
        else
          prev = g[-1][-1]

          if (m.match_line.index - prev.match_line.index <= NTH * 2 &&
              m.record.shortpath == prev.record.shortpath)
            g[-1] << m          # グループの末尾に追加
            g
          else
            g << [m]            # 新規グループ
          end
        end

        # 近接マッチ無効
        # g << [m]
      end

      @prev = nil
      
      <<EOF
#{recommended_contents}
#{match_groups.map{|g|result_match_record(g)}.join}
EOF
    end
html_pagination() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 265
    def html_pagination
      return "" if @q.empty?
      return "" if next_offset >= @total_records

      return <<EOF
<div class='pagination pagination-centered'>
#{pagination_link(next_offset, @next_line, "next >>")}
</div>
EOF
    end
make_drilldown_directories(result) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 110
def make_drilldown_directories(result)
  # Return empty if root path
  return [] if @path == ""

  # Drilldown
  files = DocumentTable.drilldown(result, "restpath")
  return [] if files.size > FILTER_BY_DIRECTORIES_FILES
  
  files.map {|v|
    Util.relative_path(v[1], @path.split("/")[1..-1].join("/")).to_s               # 'path/to/file' ->  'to/file' (@path == 'path')
  }.find_all {|v|
    v.include?("/")                                                                 # Extract directory
  }.map {|v|
    v.split("/")[0]                                                                 # 'to/file' -> 'to'
  }.inject(Hash.new(0)) {|hash, v| 
    hash[v] += 1; hash                                                              # Collect hash
  }.map {|key, value|
    [value, key]                                                                    # To Array
  }.to_a
end
match_files_contents() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 247
    def match_files_contents
      unless @match_files.empty?
        is_and_more = @match_files.size >= MATH_FILE_LIMIT
        @match_files = @match_files[0..MATH_FILE_DISP-1]
        conv_query = (@path != "") ? @q.conv_keywords_to_fpath : @q.conv_keywords_to_fpath_or_packages
        tmpp = @params.clone
        tmpp[:query] = conv_query.query_string
        url = Mkurl.new(@path, tmpp).inherit_query_shead
        <<EOF
#{@match_files.map {|record| result_record(DocumentRecord.new(record))}.join}
#{"<a href='#{url}'>...and more</a></a>" if is_and_more}
<hr>
EOF
      else
        ""
      end
    end
match_num() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 276
def match_num
  @match_records.size
end
next_offset() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 135
def next_offset
  @offset + @next_index
end
query() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 131
def query
  @q.query_string
end

Private Instance Methods

drilldown_content(array, title, to_url, prefix = "", suffix = "", disp_if_one = false) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 458
def drilldown_content(array, title, to_url, prefix = "", suffix = "", disp_if_one = false)
  unless array.empty? || (!disp_if_one && array.size == 1)
    contents = []

    array.each_with_index do |v, index|
      if v[0] != 0
        contents << "<strong><a href=\"#{to_url.call(v[1])}\" #{v[1]}(#{v[0]})>#{prefix + v[1] + suffix}</a></strong> (#{v[0]})"
      else
        contents << "..."
      end
    end

    "<div class=\"filter_list\">#{title}: " + contents.join("&nbsp;&nbsp;&nbsp;") + "</div>"
  else
    ""
  end
end
drilldown_contents() click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 439
def drilldown_contents
  contents = []
  
  result = drilldown_content(@drilldown_packages, I18n.t(:filter_by_package, {locale: @locale}), method(:refinement_directory))
  contents << result unless result.empty?

  result = drilldown_content(@drilldown_directories, I18n.t(:filter_by_directory, {locale: @locale}), method(:refinement_pathdir), '', '/', true)
  contents << result unless result.empty?

  result = drilldown_content(@drilldown_suffixs, I18n.t(:filter_by_suffix, {locale: @locale}), method(:refinement_suffix), '.')
  contents << result unless result.empty?

  unless contents.empty?
    contents.join + "<hr>\n"
  else
    ""
  end
end
grep_contents(keywords, wide_match_range) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 292
def grep_contents(keywords, wide_match_range)
  @match_records = []
  @end_index = @next_index = @records.size
  @next_line = nil

  @records.each_with_index do |record, index|
    if (Util.larger_than_oneline(record.content))
      if grep_match_lines_stopover(record, index, keywords, wide_match_range)
        break
      end
    else
      @match_records << MatchRecord.new(record, Grep::MatchLineResult.new(0, nil))

      if @match_records.size >= DISP_NUM
        @end_index = index
        @next_index = index + 1
        break
      end
    end
  end
end
grep_match_lines_stopover(record, index, keywords, wide_match_range) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 314
def grep_match_lines_stopover(record, index, keywords, wide_match_range)
  grep = Grep.new(record.content)

  if @is_onematch
    r = grep.one_match_and(keywords, @is_sensitive, wide_match_range)
  else
    r = grep.match_lines_stopover(keywords, DISP_NUM - @match_records.size, (index == 0) ? @line : 0, @is_sensitive, wide_match_range)
  end

  r[:result].each do |match_line|
    @match_records << MatchRecord.new(record, match_line) if match_line
  end

  if @match_records.size >= DISP_NUM
    if (r[:next_line] == 0)
      @end_index = index
      @next_index = index + 1
    else
      @end_index = index
      @next_index = index
      @next_line = r[:next_line]
    end
    return true
  end

  return false
end
pagination_span(content) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 385
def pagination_span(content)
  "<ul><li>#{content}</li></ul>\n"
end
refinement_directory(path) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 408
def refinement_directory(path)
  @homeurl + Mkurl.new(path, @params).inherit_query_shead
end
refinement_pathdir(dir) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 435
def refinement_pathdir(dir)
  refinement_directory(File.join(@path, dir))
end
refinement_suffix(suffix) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 402
def refinement_suffix(suffix)
  params = @params.clone
  params[:query] = [@params[:query], "s:#{suffix}"].join(" ")
  @homeurl + Mkurl.new(@path, params).inherit_query_shead
end
result_match_record(match_group) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 342
    def result_match_record(match_group)
      record = match_group[0].record

      first_index = match_group[0].match_line.index - NTH
      last_index  = match_group[-1].match_line.index + NTH
      match_lines = match_group.map{|m| m.match_line}

      coderay = CodeRayWrapper.new(record.content, record.shortpath, match_lines, @q.keywords)
      coderay.col_limit(COL_LIMIT)
      coderay.set_range(first_index..last_index)

      url = @homeurl + record_link(record)

      path = Util.relative_path(record.shortpath, @path)

      if path != @prev
#         dt = <<EOS
#     <dt class='result-record'><a href='#{url + "#n#{coderay.highlight_lines[0]}"}'>#{path}</a>#{result_refinement(record)}</dt>
# EOS
        dt = <<EOS
    <dt class='result-record'><a href='#{url + "#n#{coderay.highlight_lines[0]}"}'>#{path}</a></dt>
EOS
        @prev = path
      else
        dt = "    <dt class='result-record-empty'></dt>"
      end
      
      <<EOS
    #{dt}
    <dd>
#{coderay.to_html_anchorlink(url)}
    </dd>
EOS
    end
result_record(record) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 389
    def result_record(record)
      filename = Util.relative_path(record.shortpath, @path).to_s
      filename = Util.highlight_keywords(filename, @q.keywords, 'highlight-filename')
      
      <<EOS
    <dt class='result-file'>#{file_or_dirimg(true, @suburl)}<a href='#{@homeurl + record_link(record)}'>#{filename}</a></dt>
EOS
    end
result_refinement(record) click to toggle source
# File lib/milkode/cdweb/lib/search_contents.rb, line 412
    def result_refinement(record)
      refinements = []

      # 拡張子で絞り込み
      refinements << "<a href='#{refinement_suffix(record.suffix)}'>.#{record.suffix}</a>" if record.suffix

      # ディレクトリで絞り込み
      path    = Util.relative_path(record.shortpath, @path)
      dirname = path.to_s.split('/')[-2]
      refinements << "<a href='#{refinement_directory(record.shortpath + '/..')}'>#{dirname}/</a>" if dirname

      unless refinements.empty?
        space1            = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'
        space2            = '&nbsp;&nbsp;,&nbsp;&nbsp;'

        <<EOF
# #{space1}<span id="result-refinement">#{I18n.t(:filter, {locale: @locale})} [#{refinements.join(space2)}]</span>
EOF
      else
        ''
      end
    end