X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Fwinterwell.markdown%2Fsrc%2Fwinterwell%2Fmarkdown%2Feditors%2FFormatAction.java;fp=bundles%2Fwinterwell.markdown%2Fsrc%2Fwinterwell%2Fmarkdown%2Feditors%2FFormatAction.java;h=cd165892d39099607d04cbfe92acd725c75e2810;hp=0000000000000000000000000000000000000000;hb=2531cdf245f42bce854d43f4d49a23983c79db96;hpb=857dbc869796d772864327ce02f19dc252b159fc 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 index 000000000..cd165892d --- /dev/null +++ b/bundles/winterwell.markdown/src/winterwell/markdown/editors/FormatAction.java @@ -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 lines = page.getText(); + List 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