]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/winterwell.markdown/src/winterwell/markdown/editors/FormatAction.java
migrated to svn revision 33108
[simantics/platform.git] / bundles / winterwell.markdown / src / winterwell / markdown / editors / FormatAction.java
diff --git a/bundles/winterwell.markdown/src/winterwell/markdown/editors/FormatAction.java b/bundles/winterwell.markdown/src/winterwell/markdown/editors/FormatAction.java
new file mode 100644 (file)
index 0000000..cd16589
--- /dev/null
@@ -0,0 +1,190 @@
+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               
+       }
+       
+}