Package com.baulsupp.less

Source Code of com.baulsupp.less.Less

package com.baulsupp.less;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.regex.Pattern;

import jcurses.system.CharColor;
import jcurses.system.InputChar;
import jcurses.system.Toolkit;
import jcurses.util.Message;
import jcurses.util.Rectangle;
import jcurses.widgets.IScrollable;
import jcurses.widgets.ScrollbarPainter;

import org.apache.log4j.Logger;

import com.baulsupp.curses.list.ColorList;
import com.baulsupp.curses.list.CursesListRenderer;
import com.baulsupp.curses.list.CursesListWindow;
import com.baulsupp.curses.list.PaintListener;
import com.baulsupp.curses.list.TextDialog;
import com.baulsupp.curses.list.TextRenderer;
import com.baulsupp.curses.list.Util;
import com.baulsupp.kolja.log.filter.Filter;
import com.baulsupp.kolja.log.filter.FilteredLineIndex;
import com.baulsupp.kolja.log.filter.PriorityFilter;
import com.baulsupp.kolja.log.line.BasicLineIterator;
import com.baulsupp.kolja.log.line.Line;
import com.baulsupp.kolja.log.line.LineIndex;
import com.baulsupp.kolja.log.util.IntRange;
import com.baulsupp.kolja.log.util.WrappedCharBuffer;
import com.baulsupp.kolja.log.viewer.event.Event;
import com.baulsupp.kolja.log.viewer.event.EventList;
import com.baulsupp.kolja.log.viewer.highlight.BasicSearchHighlight;
import com.baulsupp.kolja.log.viewer.importing.LogFormat;
import com.baulsupp.kolja.log.viewer.linenumbers.BasicLineNumberIndex;
import com.baulsupp.kolja.log.viewer.renderer.FieldRenderer;
import com.baulsupp.kolja.log.viewer.renderer.Renderer;
import com.baulsupp.kolja.log.viewer.renderer.Wrap;
import com.baulsupp.kolja.log.viewer.request.RequestHighlight;
import com.baulsupp.kolja.log.viewer.request.RequestIndex;
import com.baulsupp.kolja.log.viewer.request.RequestLine;
import com.baulsupp.kolja.log.viewer.search.BasicSearch;
import com.baulsupp.kolja.log.viewer.search.Search;
import com.baulsupp.kolja.util.ColourPair;

public class Less extends CursesListWindow<Line> implements IScrollable, PaintListener {
  private static final int BACKGROUND_READAHEAD = 25000;

  private static final Logger log = Logger.getLogger(Less.class);

  private java.util.List<LineIndex> models;

  private LineIndex currentIndex;

  private java.util.List<CursesListRenderer<Line>> renderers;

  private WrappedCharBuffer buffer;

  private Search search;

  private BasicSearchHighlight basicSearchHighlight;

  private ScrollbarPainter scrollbar;
 
  private boolean drawScrollbar = false;
  private EventList eventList;
  private RequestIndex requestIndex;

  private RequestHighlight requestHighlight;
 
  private ResponsiveLock uiLock = new ResponsiveLock();
  private Lock backgroundLock = uiLock.createBackgroundLock(1500);

  public Less() {
    this.scrollbar = new ScrollbarPainter(this);

    list.addPaintListener(this);
  }

  public void open(LogFormat format, File file) throws IOException {
    buffer = WrappedCharBuffer.fromFile(file);

    loadIndexes(format);

    loadRenderer(format);

    loadLineNumbers();

    rotateFilter();
    rotateRenderer();
  }

  private void loadLineNumbers() {
    setLineNumbers(BasicLineNumberIndex.create(buffer));
  }

  private void loadIndexes(LogFormat format) {
    models = new ArrayList<LineIndex>();
   
    LineIndex li = format.getLineIndex(buffer);
    models.add(li);

    if (format.supportsEvents()) {
      eventList = format.getEventList(li);
      li.addLineListener(eventList);
    }

    // TODO move filtering to config and allow choices
    Filter filter = new PriorityFilter();
    LineIndex filteredIndex = new FilteredLineIndex(li, filter);
    models.add(filteredIndex);

    if (format.supportsRequests()) {
      requestIndex = format.getRequestIndex(li);
    }
  }

  private void loadRenderer(LogFormat format) {
    renderers = new ArrayList<CursesListRenderer<Line>>();
   
    Renderer<Line> gridNonWrapped = format.getRenderer();
    gridNonWrapped.setWidth(Toolkit.getScreenWidth());
   
    ViewRowRenderer viewRenderer = new ViewRowRenderer(gridNonWrapped);
    renderers.add(viewRenderer);

    basicSearchHighlight = new BasicSearchHighlight(ColourPair.RED_ON_BLACK);
   
    if (gridNonWrapped instanceof FieldRenderer) {
      ((FieldRenderer) gridNonWrapped).addHighlight(basicSearchHighlight);
      ((FieldRenderer) gridNonWrapped).setWrappingMode(Wrap.NONE);
     
      Renderer<Line> gridWrapped = format.getRenderer();
      gridWrapped.setWidth(Toolkit.getScreenWidth());
      ((FieldRenderer) gridWrapped).setWrappingMode(Wrap.LAST_COLUMN);
      ((FieldRenderer) gridWrapped).addHighlight(basicSearchHighlight);

      if (format.supportsRequests()) { 
        requestHighlight = new RequestHighlight(ColourPair.MAGENTA_ON_BLACK, requestIndex, null);

        ((FieldRenderer) gridWrapped).addHighlight(requestHighlight);
        ((FieldRenderer) gridNonWrapped).addHighlight(requestHighlight);
      }
     
      viewRenderer = new ViewRowRenderer(gridWrapped);
      renderers.add(viewRenderer);
    }

    TextRenderer<Line> plain = new TextRenderer<Line>();
    plain.setWrapping(Toolkit.getScreenWidth());
    renderers.add(plain);

    TextRenderer<Line> plainUnwrapped = new TextRenderer<Line>();
    plainUnwrapped.setWrapping(TextRenderer.NO_WRAP);
    renderers.add(plainUnwrapped);
  }
 
  public boolean handleInput(InputChar inp) {
    try {
      uiLock.lock();
     
      return internalHandleInput(inp);
    } finally {
      uiLock.unlock();
    }
  }

  public boolean internalHandleInput(InputChar inp) {
    try {
      if (Util.wasLetter(inp, 'f'))
        rotateFilter();
      else if (Util.wasLetter(inp, '?'))
        showHelp();
      else if (Util.wasLetter(inp, 'r'))
        rotateRenderer();
      else if (supportsSearch() && Util.wasLetter(inp, '/'))
        newSearch();
      else if (Util.wasLetter(inp, 'n'))
        nextSearchResult();
      else if (Util.wasLetter(inp, 'p'))
        previousSearchResult();
      else if (Util.wasLetter(inp, 's'))
        toggleScrollbar();
      else if (Util.wasLetter(inp, 'e'))
        selectEvent();
      else if (Util.wasLetter(inp, 't'))
        selectRequest();
      else
        return super.handleInput(inp);
    } catch (Exception e) {
      log.error("error", e);
      shutdown();
    }

    return true;
  }

  private void selectEvent() {
    if (eventList != null) {
      Event e = EventDialog.getValue(eventList);

      if (e != null) {
        log.info("selected " + e + " moving to " + e.getOffset());
        list.moveTo(e.getOffset());
      } else {
        log.info("no request selected");
      }
    }
  }

  private void selectRequest() {
    if (requestIndex != null) {
      RequestLine l = RequestDialog.getValue(requestIndex, list.getOffset());

      if (l != null) {
        log.info("selected " + l + " moving to " + l.getOffset());
        requestHighlight.setValue(l.getIdentifier());
        list.moveTo(l.getMinimumKnownOffset());
      } else {
        log.info("no request selected");
      }
    }
  }

  private void toggleScrollbar() {
    if (drawScrollbar) {
      drawScrollbar = false;
    } else {
      drawScrollbar = true;
    }

    list.doPaint();
  }

  void showHelp() {
    new Message("Help", "Help\nUse arrow keys to move.  q to quit.", "ok").show();
  }

  void rotateFilter() {
    setModel(getNextLineModel());
  }

  void setModel(LineIndex li) {
    currentIndex = li;
    list.setModel(new LineIndexItemModel(new BasicLineIterator(li)));

    if (search != null) {
      search.setModel(new LineIndexItemModel(new BasicLineIterator(currentIndex)));
    }
  }

  LineIndex getNextLineModel() {
    LineIndex li = (LineIndex) models.remove(0);
    models.add(li);

    return li;
  }

  void rotateRenderer() {
    CursesListRenderer<Line> nextRenderer = getNextRenderer();

    if (nextRenderer instanceof ViewRowRenderer) {
      ViewRowRenderer viewRenderer = (ViewRowRenderer) nextRenderer;
     
      if (viewRenderer.getRenderer() instanceof FieldRenderer) {
        FieldRenderer fieldRenderer = (FieldRenderer) viewRenderer.getRenderer();
        list.setSidewaysSteps(fieldRenderer.getWidths().getSteps());
      }
    } else {
      list.setSidewaysSteps(null);
    }
   
    list.setSidewaysMove(10);
   
    list.setRenderer(nextRenderer);
  }

  CursesListRenderer<Line> getNextRenderer() {
    CursesListRenderer<Line> r = (CursesListRenderer<Line>) renderers.remove(0);
    renderers.add(r);

    return r;
  }

  protected boolean supportsSearch() {
    return true;
  }

  protected void newSearch() {
    String a = TextDialog.getValue("Search");

    Pattern pattern = Pattern.compile(a);

    search = new BasicSearch(pattern);

    search.setModel(new LineIndexItemModel(new BasicLineIterator(currentIndex)));

    basicSearchHighlight.setPattern(pattern);

    nextSearchResult();
  }

  private boolean hasCurrentSearch() {
    return search != null;
  }

  private void nextSearchResult() {
    if (hasCurrentSearch()) {
      int pos = search.next(list.getOffset());

      if (pos != -1) {
        list.moveTo(pos);
      }
    }
  }

  private void previousSearchResult() {
    if (hasCurrentSearch()) {
      int pos = search.previous(list.getOffset());

      if (pos != -1) {
        list.moveTo(pos);
      }
    }
  }


  public boolean hasHorizontalScrollbar() {
    return false;
  }

  public boolean hasVerticalScrollbar() {
    return true;
  }

  public Rectangle getBorderRectangle() {
    Rectangle r = list.getRectangle();
   
    // account for normal (unwanted) margin
    r.setY(-1);
    r.setHeight(r.getHeight() + 2);
   
    r.setX(r.getX() + r.getWidth() - 1);
    r.setWidth(1);
    return r;
  }

  public CharColor getBorderColors() {
    return ColorList.blackOnWhite;
  }

  public CharColor getScrollbarColors() {
    return ColorList.yellowOnBlack;
  }

  public float getHorizontalScrollbarOffset() {
    return 0;
  }

  public float getHorizontalScrollbarLength() {
    return 0;
  }

  public float getVerticalScrollbarOffset() {
    float offset = list.getOffset();
    float total = buffer.length();
   
    return offset / total;
  }

  public float getVerticalScrollbarLength() {
    float firstOffset = list.getOffset();
    float lastOffset = list.getLastOffset();
    float total = buffer.length();

    return (lastOffset - firstOffset) / total;
  }

  public void painted() {
    uiLock.startBackgroundThreads();
   
    if (drawScrollbar) {
      if (log.isInfoEnabled()) {
        log.info("scrollbar " + getVerticalScrollbarOffset() + " " + getVerticalScrollbarLength());
      }
      scrollbar.paint();
    }
  }

  public void startBackgroundThread() {
    if (eventList != null) {
      Thread t = new Thread("Less-BackgroundThread") {
        @Override
        public void run() {
          try {
            processMore();
          } catch (Exception e) {
            log.error("exception", e);
          }
        }
      };
      t.start();
    }
  }

  protected void processMore() {
    while (true) {
      boolean more = false;
     
      backgroundLock.lock();
     
      try {
        more = processSlightlyMore();
      } finally {
        backgroundLock.unlock();
      }
     
      if (!more) {
        sleep(5000);
      }
    }
  }
 
  private void sleep(long ms) {
    try {
      Thread.sleep(ms);
    } catch (InterruptedException e) {
      // nothing
    }
  }

  private boolean processSlightlyMore() {
    IntRange[] unknown = eventList.listUnknown();
   
    if (unknown.length == 0) {
      log.info("nothing to process");

      return false;
    } else {
      IntRange first = new IntRange(unknown[0]);
     
      if (first.getLength() > BACKGROUND_READAHEAD) {
        first.setTo(first.getFrom() + BACKGROUND_READAHEAD);
      }
     
      log.info("ensuring known " + first);
     
      eventList.ensureKnown(first);
     
      return true;
    }
  }
}
TOP

Related Classes of com.baulsupp.less.Less

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.