<commit_before>/**
 * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Eclipse Public License (EPL).
 * Please see the license.txt included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
/*
 * Created on Feb 22, 2005
 *
 * @author <NAME>
 */
package org.python.pydev.editor.actions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.python.pydev.core.ExtensionHelper;
import org.python.pydev.core.IPyEdit;
import org.python.pydev.core.Tuple3;
import org.python.pydev.core.docutils.ParsingUtils;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.docutils.SyntaxErrorException;
import org.python.pydev.core.log.Log;
import org.python.pydev.core.structure.FastStringBuffer;
import org.python.pydev.editor.PyEdit;
import org.python.pydev.parser.prettyprinterv2.IFormatter;
import org.python.pydev.plugin.preferences.PyCodeFormatterPage;

/**
 * @author <NAME>
 */
public class PyFormatStd extends PyAction implements IFormatter {

    /**
     * Class that defines the format standard to be used
     *
     * @author Fabio
     */
    public static class FormatStd {
        
        /**
         * Defines whether spaces should be added after a comma
         */
        public boolean spaceAfterComma;

        /**
         * Defines whether ( and ) should have spaces
         */
        public boolean parametersWithSpace;
        
        /**
         * Defines whether = should be spaces surrounded when inside of a parens (function call)
         * (as well as others related: *= +=, -=, !=, ==, etc).
         */
        public boolean assignWithSpaceInsideParens;
        
        /**
         * Defines whether operators should be spaces surrounded:
         * + - * / // ** | & ^ ~ =
         */
        public boolean operatorsWithSpace;

        public boolean addNewLineAtEndOfFile;

        public boolean trimLines;
    }
    
    

    /**
     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
     */
    public void run(IAction action) {
        try {
        	if(!canModifyEditor()){
        		return;
        	}

            PyEdit pyEdit = getPyEdit();
            PySelection ps = new PySelection(pyEdit);
            
            
            try{
                IRegion[] regionsToFormat = null;
                if(ps.getSelLength() > 0){
                    //Create a region with the full lines selected for the formatting.
                    IDocument doc = ps.getDoc();
                    IRegion start = doc.getLineInformation(ps.getStartLineIndex());
                    IRegion end = doc.getLineInformation(ps.getEndLineIndex());
                
                    int iStart = start.getOffset();
                    int iEnd = end.getOffset() + end.getLength();
                    regionsToFormat = new IRegion[]{new Region(iStart, iEnd-iStart)};
                }

                applyFormatAction(pyEdit, ps, regionsToFormat, true);
            }catch(SyntaxErrorException e){
                pyEdit.getStatusLineManager().setErrorMessage(e.getMessage());
            }

        } catch (Exception e) {
            beep(e);
        }
    }

    
    /**
     * This method applies the code-formatting to the document in the PySelection
     * 
     * @param pyEdit used to restore the selection
     * @param ps the selection used (contains the document that'll be changed)
     * @param regionsToFormat if null or empty, the whole document will be formatted, otherwise, only the passed ranges will
     * be formatted. 
     * @throws SyntaxErrorException 
     */
    public void applyFormatAction(PyEdit pyEdit, PySelection ps, IRegion[] regionsToFormat, boolean throwSyntaxError) throws BadLocationException, SyntaxErrorException {
        final IFormatter participant = getFormatter();
        final IDocument doc = ps.getDoc();
        final SelectionKeeper selectionKeeper = new SelectionKeeper(ps);
        
        DocumentRewriteSession session = null;
        try{
        
            if (regionsToFormat == null || regionsToFormat.length == 0) {
                if(doc instanceof IDocumentExtension4){
                    IDocumentExtension4 ext = (IDocumentExtension4) doc;
                    session = ext.startRewriteSession(DocumentRewriteSessionType.STRICTLY_SEQUENTIAL);
                }
                participant.formatAll(doc, pyEdit, true, throwSyntaxError);
            } else {
                if(doc instanceof IDocumentExtension4){
                    IDocumentExtension4 ext = (IDocumentExtension4) doc;
                    session = ext.startRewriteSession(DocumentRewriteSessionType.SEQUENTIAL);
                }
                participant.formatSelection(doc, regionsToFormat, pyEdit, ps);
            }

            //To finish, no matter what kind of formatting was done, check the end of line.
            FormatStd std = getFormat();
            if(std.addNewLineAtEndOfFile){
                try {
                    int len = doc.getLength();
                    char lastChar = doc.getChar(len-1);
                    if(len > 0){
                        if(lastChar != '\r' && lastChar != '\n'){
                            doc.replace(len, 0, PySelection.getDelimiter(doc));
                        }
                    }
                } catch (Throwable e) {
                    Log.log(e);
                }
            }

            
        }finally{
            if(session != null){
                ((IDocumentExtension4)doc).stopRewriteSession(session);
            }
        }
<commit_msg>Fixed issue when saving empty document (bad location on code-formatter).<commit_after>/**
 * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Eclipse Public License (EPL).
 * Please see the license.txt included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
/*
 * Created on Feb 22, 2005
 *
 * @author <NAME>
 */
package org.python.pydev.editor.actions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentRewriteSession;
import org.eclipse.jface.text.DocumentRewriteSessionType;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentExtension4;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.python.pydev.core.ExtensionHelper;
import org.python.pydev.core.IPyEdit;
import org.python.pydev.core.Tuple3;
import org.python.pydev.core.docutils.ParsingUtils;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.docutils.SyntaxErrorException;
import org.python.pydev.core.log.Log;
import org.python.pydev.core.structure.FastStringBuffer;
import org.python.pydev.editor.PyEdit;
import org.python.pydev.parser.prettyprinterv2.IFormatter;
import org.python.pydev.plugin.preferences.PyCodeFormatterPage;

/**
 * @author <NAME>
 */
public class PyFormatStd extends PyAction implements IFormatter {

    /**
     * Class that defines the format standard to be used
     *
     * @author Fabio
     */
    public static class FormatStd {
        
        /**
         * Defines whether spaces should be added after a comma
         */
        public boolean spaceAfterComma;

        /**
         * Defines whether ( and ) should have spaces
         */
        public boolean parametersWithSpace;
        
        /**
         * Defines whether = should be spaces surrounded when inside of a parens (function call)
         * (as well as others related: *= +=, -=, !=, ==, etc).
         */
        public boolean assignWithSpaceInsideParens;
        
        /**
         * Defines whether operators should be spaces surrounded:
         * + - * / // ** | & ^ ~ =
         */
        public boolean operatorsWithSpace;

        public boolean addNewLineAtEndOfFile;

        public boolean trimLines;
    }
    
    

    /**
     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
     */
    public void run(IAction action) {
        try {
        	if(!canModifyEditor()){
        		return;
        	}

            PyEdit pyEdit = getPyEdit();
            PySelection ps = new PySelection(pyEdit);
            
            
            try{
                IRegion[] regionsToFormat = null;
                if(ps.getSelLength() > 0){
                    //Create a region with the full lines selected for the formatting.
                    IDocument doc = ps.getDoc();
                    IRegion start = doc.getLineInformation(ps.getStartLineIndex());
                    IRegion end = doc.getLineInformation(ps.getEndLineIndex());
                
                    int iStart = start.getOffset();
                    int iEnd = end.getOffset() + end.getLength();
                    regionsToFormat = new IRegion[]{new Region(iStart, iEnd-iStart)};
                }

                applyFormatAction(pyEdit, ps, regionsToFormat, true);
            }catch(SyntaxErrorException e){
                pyEdit.getStatusLineManager().setErrorMessage(e.getMessage());
            }

        } catch (Exception e) {
            beep(e);
        }
    }

    
    /**
     * This method applies the code-formatting to the document in the PySelection
     * 
     * @param pyEdit used to restore the selection
     * @param ps the selection used (contains the document that'll be changed)
     * @param regionsToFormat if null or empty, the whole document will be formatted, otherwise, only the passed ranges will
     * be formatted. 
     * @throws SyntaxErrorException 
     */
    public void applyFormatAction(PyEdit pyEdit, PySelection ps, IRegion[] regionsToFormat, boolean throwSyntaxError) throws BadLocationException, SyntaxErrorException {
        final IFormatter participant = getFormatter();
        final IDocument doc = ps.getDoc();
        final SelectionKeeper selectionKeeper = new SelectionKeeper(ps);
        
        DocumentRewriteSession session = null;
        try{
        
            if (regionsToFormat == null || regionsToFormat.length == 0) {
                if(doc instanceof IDocumentExtension4){
                    IDocumentExtension4 ext = (IDocumentExtension4) doc;
                    session = ext.startRewriteSession(DocumentRewriteSessionType.STRICTLY_SEQUENTIAL);
                }
                participant.formatAll(doc, pyEdit, true, throwSyntaxError);
            } else {
                if(doc instanceof IDocumentExtension4){
                    IDocumentExtension4 ext = (IDocumentExtension4) doc;
                    session = ext.startRewriteSession(DocumentRewriteSessionType.SEQUENTIAL);
                }
                participant.formatSelection(doc, regionsToFormat, pyEdit, ps);
            }

            //To finish, no matter what kind of formatting was done, check the end of line.
            FormatStd std = getFormat();
            if(std.addNewLineAtEndOfFile){
                try {
                    int len = doc.getLength();
                    if(len > 0){
                        char lastChar = doc.getChar(len-1);
                        if(lastChar != '\r' && lastChar != '\n'){
                            doc.replace(len, 0, PySelection.getDelimiter(doc));
                        }
                    }
                } catch (Throwable e) {
                    Log.log(e);
                }
            }

            
        }finally{
            if(session != null){
                ((IDocumentExtension4)doc).stopRewriteSession(session);
            }
        }

{'fraction_non_alphanumeric': 0.09118441515920439, 'fraction_numerical': 0.004747483015470246, 'mean_word_length': 1.996076508092202, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3112488', 'n_tokens_mistral': 3293, 'n_tokens_neox': 3117, 'n_words': 805}