summary refs log tree commit diff stats
path: root/compiler/prefixmatches.nim
blob: 246d1ae5e0c47d261288aca3e157212ce099b359 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#
#
#           The Nim Compiler
#        (c) Copyright 2017 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

from strutils import toLowerAscii

type
  PrefixMatch* {.pure.} = enum
    None,   ## no prefix detected
    Abbrev  ## prefix is an abbreviation of the symbol
    Substr, ## prefix is a substring of the symbol
    Prefix, ## prefix does match the symbol

proc prefixMatch*(p, s: string): PrefixMatch =
  template eq(a, b): bool = a.toLowerAscii == b.toLowerAscii
  if p.len > s.len: return PrefixMatch.None
  var i = 0
  let L = s.len
  # check for prefix/contains:
  while i < L:
    if s[i] == '_': inc i
    if i < L and eq(s[i], p[0]):
      var ii = i+1
      var jj = 1
      while ii < L and jj < p.len:
        if p[jj] == '_': inc jj
        if s[ii] == '_': inc ii
        if not eq(s[ii], p[jj]): break
        inc ii
        inc jj

      if jj >= p.len:
        if i == 0: return PrefixMatch.Prefix
        else: return PrefixMatch.Substr
    inc i
  # check for abbrev:
  if eq(s[0], p[0]):
    i = 1
    var j = 1
    while i < s.len:
      if i < s.len-1 and s[i] == '_':
        if j < p.len and eq(p[j], s[i+1]): inc j
        else: return PrefixMatch.None
      if i < s.len and s[i] in {'A'..'Z'} and s[i-1] notin {'A'..'Z'}:
        if j < p.len and eq(p[j], s[i]): inc j
        else: return PrefixMatch.None
      inc i
    if j >= p.len:
      return PrefixMatch.Abbrev
    else:
      return PrefixMatch.None
  return PrefixMatch.None

when isMainModule:
  import macros

  macro check(val, body: untyped): untyped =
    result = newStmtList()
    expectKind body, nnkStmtList
    for b in body:
      expectKind b, nnkPar
      expectLen b, 2
      let p = b[0]
      let s = b[1]
      result.add quote do:
        echo prefixMatch(`p`, `s`) == `val`

  check PrefixMatch.Prefix:
    ("abc", "abc")
    ("a", "abc")
    ("xyz", "X_yzzzZe")

  check PrefixMatch.Substr:
    ("b", "abc")
    ("abc", "fooabcabc")
    ("abC", "foo_AB_c")

  check PrefixMatch.Abbrev:
    ("abc", "AxxxBxxxCxxx")
    ("xyz", "X_yabcZe")

  check PrefixMatch.None:
    ("foobar", "afkslfjd_as")
    ("xyz", "X_yuuZuuZe")
    ("ru", "remotes")
init__(self, win, ratios, preview = True): DisplayableContainer.__init__(self, win) from functools import reduce self.ratios = ratios self.preview = preview # normalize ratios: ratio_sum = float(reduce(lambda x,y: x + y, ratios)) self.ratios = tuple(map(lambda x: x / ratio_sum, ratios)) if len(self.ratios) >= 2: self.stretch_ratios = self.ratios[:-2] + \ ((self.ratios[-2] + self.ratios[-1] * 0.9), \ (self.ratios[-1] * 0.1)) offset = 1 - len(ratios) if preview: offset += 1 for level in range(len(ratios)): fl = FileList(win, level + offset) self.add_obj(fl) try: self.main_filelist = self.container[preview and -2 or -1] except IndexError: self.main_filelist = None else: self.main_filelist.display_infostring = True self.main_filelist.main_display = True def resize(self, y, x, hei, wid): """Resize all the filelists according to the given ratio""" DisplayableContainer.resize(self, y, x, hei, wid) left = self.x cut_off_last = self.preview and not self.preview_available \ and self.stretch_ratios if cut_off_last: generator = zip(self.stretch_ratios, range(len(self.ratios))) else: generator = zip(self.ratios, range(len(self.ratios))) for ratio, i in generator: wid = int(ratio * self.wid) if i == len(self.ratios) - 1: wid = int(self.wid - left + 1) try: self.container[i].resize(self.y, left, hei, max(1, wid-1)) except KeyError: pass left += wid def poke(self): DisplayableContainer.poke(self) if self.settings.collapse_preview and self.preview: has_preview = self.container[-1].has_preview() if self.preview_available != has_preview: self.preview_available = has_preview self.resize(self.y, self.x, self.hei, self.wid)