Package winterwell.markdown.editors

Source Code of winterwell.markdown.editors.FormatAction

package winterwell.markdown.editors;

import java.util.List;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.commands.IHandlerListener;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.source.ISourceViewer;

import winterwell.markdown.pagemodel.MarkdownFormatter;
import winterwell.markdown.pagemodel.MarkdownPage;
import winterwell.markdown.pagemodel.MarkdownPage.KLineType;
import winterwell.utils.containers.IntRange;

/**
* TODO An action for formatting text (via hard wrapping, i.e. inserting returns).
*
*
* @author daniel
*/
public class FormatAction extends Action implements IHandler {

  public FormatAction() {
    super("&Format paragraph");
    setActionDefinitionId("winterwell.markdown.formatParagraphCommand");
    setToolTipText("Format the paragraph under the caret by inserting/removing line-breaks");
  }
 
  @Override
  public void run() {
    try {
      MarkdownEditor ed = (MarkdownEditor) ActionBarContributor.getActiveEditor();
      if (ed == null) return; // The active editor is not a markdown editor.
      int cols = ed.getPrintColumns();
      // Do we have a selection?
      ITextSelection s = (ITextSelection) ed.getSelectionProvider().getSelection();
      if (s != null && s.getLength() > 0) {
        formatSelectedRegion(ed, s, cols);
        return;
      }
      // Where is the caret?
      ISourceViewer viewer = ed.getViewer();
      int caretOffset = viewer.getTextWidget().getCaretOffset();
      int lineNum = ed.getDocument().getLineOfOffset(caretOffset);
      // Get a paragraph region
      MarkdownPage page = ed.getMarkdownPage();
      IRegion pRegion = getParagraph(page, lineNum, ed.getDocument());
      if (pRegion==null) {
        // Not in a paragraph - so give up
         // TODO tell the user why we've given up
        return;
      }
      String paragraph = ed.getDocument().get(pRegion.getOffset(), pRegion.getLength());
      // Format
      String formatted = MarkdownFormatter.format(paragraph, cols);
      if (formatted.equals(paragraph)) return; // No change!
      // Replace the unformatted region with the new formatted one
      ed.getDocument().replace(pRegion.getOffset(), pRegion.getLength(), formatted);
      // Done
    } catch (Exception ex) {
      System.out.println(ex);
    }
  }

  private void formatSelectedRegion(MarkdownEditor ed, ITextSelection s, int cols)
  throws BadLocationException {
    int start = s.getStartLine();
    int end = s.getEndLine();
    IDocument doc = ed.getDocument();
    int soff = doc.getLineOffset(start);
    int eoff = lineEndOffset(end, doc);   
    IntRange editedRegion = new IntRange(soff, eoff);   
    MarkdownPage page = ed.getMarkdownPage();
    StringBuilder sb = new StringBuilder(s.getLength());
    for(int i=start; i<=end; i++) {
      IRegion para = getParagraph(page, i, ed.getDocument());
      if (para==null) {
        sb.append(page.getText().get(i));
        continue;
      }
      String paragraph = ed.getDocument().get(para.getOffset(), para.getLength());
//      int lines = StrUtils.splitLines(paragraph).length;
      String formatted = MarkdownFormatter.format(paragraph, cols);
      // append formatted and move forward
      sb.append(formatted);
      CharSequence le = lineEnd(i, doc);
      sb.append(le);
      int pEnd = doc.getLineOfOffset(para.getOffset()+para.getLength());
      i = pEnd;
      // Adjust edited region?
      IntRange pr = new IntRange(para.getOffset(),
          para.getOffset()+para.getLength()+le.length());     
      editedRegion = new IntRange(Math.min(pr.low, editedRegion.low),
                    Math.max(pr.high, editedRegion.high));     
    }   
    // Replace the unformatted region with the new formatted one
    String old = doc.get(editedRegion.low, editedRegion.size());
    String newText = sb.toString();
    if (old.equals(newText)) return;
    ed.getDocument().replace(editedRegion.low, editedRegion.size(), newText);   
  }

  private CharSequence lineEnd(int line, IDocument doc) throws BadLocationException {
    int eoff = doc.getLineOffset(line) + doc.getLineInformation(line).getLength();   
    char c = doc.getChar(eoff);
    if (c=='\r' && doc.getLength() > eoff+1
        && doc.getChar(eoff+1) =='\n') return "\r\n";
    return ""+c;
  }

  private int lineEndOffset(int end, IDocument doc)
  throws BadLocationException {
    int eoff = doc.getLineOffset(end) + doc.getLineInformation(end).getLength();
    // Include line end
    char c = doc.getChar(eoff);
    if (c=='\r' && doc.getLength() > eoff+1
        && doc.getChar(eoff+1) =='\n') eoff += 2;
    else eoff += 1;
    return eoff;
  }

  /**
   *
   * @param page
   * @param lineNum
   * @param doc
   * @return region of paragraph containing this line, or null
   * @throws BadLocationException
   */
  private IRegion getParagraph(MarkdownPage page, int lineNum, IDocument doc)
  throws BadLocationException {
    // Get doc info
    List<String> lines = page.getText();
    List<KLineType> lineInfo = page.getLineTypes();
    // Check we are in a paragraph or list
    KLineType pType = lineInfo.get(lineNum);
    switch(pType) {
    case NORMAL: break;
    default: // Not in a paragraph, so we cannot format. 
      return null;
    }
    // Work out the paragraph
    // Beginning
    int start;
    for(start=lineNum; start>-1; start--) {
      if (lineInfo.get(start) != pType) {
        start++;
        break;
      }
    }
    // End
    int end;
    for(end=lineNum; end<lines.size(); end++) {
      if (lineInfo.get(end) != pType) {
        end--;
        break;
      }
    }
    // Get offset info
    int sOff = doc.getLineOffset(start);
    IRegion endLine = doc.getLineInformation(end)// exclude final line end
    int eOff = endLine.getOffset()+endLine.getLength();
    return new Region(sOff, eOff-sOff);
  }

  public void addHandlerListener(IHandlerListener handlerListener) {
    // Ignore
  }

  public void dispose() {
    // Ignore   
  }

  public Object execute(ExecutionEvent event) throws ExecutionException {
    run();
    return null;
  }

  public void removeHandlerListener(IHandlerListener handlerListener) {
    // Ignore   
  }
 
}
TOP

Related Classes of winterwell.markdown.editors.FormatAction

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.