import contextlib
import curses
import os
import sys

import fzsl

for i, color in enumerate(('white', 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan')):
    vars()['COL_%s' % (color.upper())] = i
    vars()['COL_B%s' % (color.upper())] = i + 8


@contextlib.contextmanager
def ncurses():
    # Push stdout to stderr so that we still get the curses
    # output while inside of a pipe or subshell
    old_stdout = sys.__stdout__
    old_stdout_fd = os.dup(sys.stdout.fileno())
    os.dup2(sys.stderr.fileno(), sys.stdout.fileno())

    scr = curses.initscr()
    curses.start_color()
    curses.use_default_colors()
    _ = [curses.init_pair(i + 1, i, -1) for i in range(curses.COLORS)]

    curses.noecho()
    curses.cbreak()
    curses.raw()
    curses.curs_set(0)

    scr.keypad(1)

    exc = None
    try:
        yield scr
    #pylint: disable=W0703
    except Exception:
        exc = sys.exc_info()

    scr.keypad(0)
    curses.nocbreak()
    curses.echo()
    curses.endwin()

    os.dup2(old_stdout_fd, sys.stdout.fileno())
    sys.stdout = old_stdout

    if exc is not None:
        raise exc[0], exc[1], exc[2]


class SimplePager(object):
    def __init__(self, scr):
        super(SimplePager, self).__init__()
        self._scr = scr

        self._config = {
            'default': 'find ./'
        }
        self._show_score = False
        self._fm = fzsl.FuzzyMatch()
        self._selection = 0

        max_y, _ = self._scr.getmaxyx()
        self._max_y = max_y - 1

    def run(self):
        scanner = fzsl.Scanner(self._config)

        self._scr.addstr("Scanning ...")
        self._scr.refresh()
        files = scanner.scan()
        self._fm.add_files(files)

        search = ''

        def draw():
            self._scr.erase()
            m = self._fm.top_matches(self._max_y)
            if self._selection >= len(m):
                self._selection = max(len(m) - 1, 0)

            for index, match in enumerate(m):
                if len(search) > 0 and self._fm.score(match) == 0:
                    continue

                prefix = ''
                if self._show_score:
                    prefix = "%f     " % (self._fm.score(match),)
                offset = len(prefix)


                start = self._fm.start(match)
                end = self._fm.end(match)

                if self._selection == index:
                    self._scr.addstr(self._max_y - index - 1, 0, prefix + match[:start], curses.A_UNDERLINE)
                    self._scr.addstr(self._max_y - index - 1, start+offset, match[start:end], curses.A_UNDERLINE|curses.color_pair(COL_BCYAN))
                    self._scr.addstr(self._max_y - index - 1, end+offset, match[end:], curses.A_UNDERLINE)
                else:
                    self._scr.addstr(self._max_y - index - 1, 0, prefix + match[:start])
                    self._scr.addstr(self._max_y - index - 1, start+offset, match[start:end], curses.color_pair(COL_BCYAN))
                    self._scr.addstr(self._max_y - index - 1, end+offset, match[end:])

            self._scr.addstr(self._max_y, 2, "%d/%d >  %s" % (self._fm.n_matches, self._fm.n_files, search))
            self._scr.refresh()


        draw()

        # Read from stdin instead of using curses.getch  so we can
        # differentiate between ctrl+j and enter, and similar.
        while True:
            c = ord(sys.stdin.read(1))

            if c == 13:
                # enter
                break
            elif c in (66, 10):
                # down arrow, ctrl+j
                self._selection = self._selection - 1 if self._selection > 0 else 0
            elif c in (65, 11):
                # up arrow, ctrl+k
                self._selection = self._selection + 1 if self._selection < self._max_y - 2 else self._selection
            elif c == 22:
                # ctrl+v
                self._show_score = not self._show_score
            elif c == 27:
                # escape
                return ''
            else:
                if c in (126, 127):
                    # delete, backspace
                    if len(search):
                        search = search[:-1]
                else:
                    search += chr(c)

                self._fm.update_scores(search)

            draw()

        return self._fm.top_matches(self._max_y)[self._selection]


def main():
    with ncurses() as scr:
        ui = SimplePager(scr)
        result = ui.run()
    sys.stdout.write(result.strip())

if __name__ == '__main__':
    main()

@@ -1424,16 +1424,42 @@
 tion = 0
+%0A        self._search = ''
 %0A%0A      
@@ -1729,28 +1729,8 @@
 s)%0A%0A
-        search = ''%0A
 %0A   
@@ -1987,24 +1987,30 @@
      if len(
+self._
 search) %3E 0 
@@ -3157,16 +3157,22 @@
 _files, 
+self._
 search))
@@ -4119,16 +4119,22 @@
  if len(
+self._
 search):
@@ -4154,24 +4154,30 @@
             
+self._
 search = sea
@@ -4173,16 +4173,22 @@
 earch = 
+self._
 search%5B:
@@ -4233,16 +4233,22 @@
         
+self._
 search +
@@ -4296,16 +4296,22 @@
 _scores(
+self._
 search)%0A

move search to SimplePager attribute