/******************************************************************************* * Copyright (c) 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.ui.editor.saveparticipant; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.dltk.annotations.NonNull; import org.eclipse.dltk.annotations.Nullable; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.PreferencesLookupDelegate; import org.eclipse.dltk.core.manipulation.SourceModuleChange; import org.eclipse.dltk.ui.editor.saveparticipant.IPostSaveListener; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.ltk.core.refactoring.TextFileChange; import org.eclipse.php.internal.core.preferences.PreferencesSupport; import org.eclipse.php.internal.ui.PHPUiPlugin; import org.eclipse.php.internal.ui.preferences.PreferenceConstants; import org.eclipse.text.edits.DeleteEdit; import org.eclipse.text.edits.MultiTextEdit; import org.eclipse.wst.jsdt.internal.ui.javaeditor.saveparticipant.SaveParticipantDescriptor; public class RemoveTrailingWhitespacesSaveParticipant implements IPostSaveListener { @Override public String getName() { return "Remove trailing whitespaces"; //$NON-NLS-1$ } @Override public String getId() { return ID; } public static final String ID = "RemoveTrailingWhitespaces"; //$NON-NLS-1$ /** * Preference prefix that is appended to the id of * {@link SaveParticipantDescriptor save participants}. * * <p> * Value is of type <code>Boolean</code>. * </p> */ public static final String EDITOR_SAVE_PARTICIPANT_PREFIX = "editor_save_participant_"; //$NON-NLS-1$ private boolean removeTrailingWhitespacesEnabled = false; private boolean ignoreEmptyLines = false; /* * Gets the preferences set for this editor in the Save Actions section */ public void updateSaveActionsState(@Nullable IProject project) { PreferencesSupport prefSupport = new PreferencesSupport(PHPUiPlugin.ID); String doCleanupPref = prefSupport.getPreferencesValue(PreferenceConstants.FORMAT_REMOVE_TRAILING_WHITESPACES, null, project); String ignoreEmptyPref = prefSupport.getPreferencesValue( PreferenceConstants.FORMAT_REMOVE_TRAILING_WHITESPACES_IGNORE_EMPTY, null, project); removeTrailingWhitespacesEnabled = Boolean.parseBoolean(doCleanupPref); ignoreEmptyLines = Boolean.parseBoolean(ignoreEmptyPref); } @Override public boolean isEnabled(ISourceModule compilationUnit) { return new PreferencesLookupDelegate(compilationUnit.getScriptProject().getProject()).getBoolean(PHPUiPlugin.ID, EDITOR_SAVE_PARTICIPANT_PREFIX + ID); } @Override public boolean needsChangedRegions(ISourceModule compilationUnit) throws CoreException { return false; } protected @NonNull MultiTextEdit computeTextEdit(@NonNull IDocument document) throws BadLocationException { int lineCount = document.getNumberOfLines(); MultiTextEdit multiEdit = new MultiTextEdit(); for (int i = 0; i < lineCount; i++) { IRegion region = document.getLineInformation(i); if (region.getLength() == 0) { continue; } int lineStart = region.getOffset(); int lineExclusiveEnd = lineStart + region.getLength(); int j = lineExclusiveEnd - 1; while (j >= lineStart && Character.isWhitespace(document.getChar(j))) { --j; } ++j; // A flag for skipping empty lines, if required if (ignoreEmptyLines && j == lineStart) { continue; } if (j < lineExclusiveEnd) { multiEdit.addChild(new DeleteEdit(j, lineExclusiveEnd - j)); } } return multiEdit; } @Override public void saved(ISourceModule compilationUnit, IRegion[] changedRegions, IProgressMonitor monitor) throws CoreException { IScriptProject project = compilationUnit.getScriptProject(); updateSaveActionsState(project != null ? project.getProject() : null); if (!removeTrailingWhitespacesEnabled) { return; } try { IDocument document = new Document(compilationUnit.getSource()); MultiTextEdit edits = computeTextEdit(document); if (edits.hasChildren()) { final SourceModuleChange change = new SourceModuleChange( "Remove trailing whitespaces from " + compilationUnit.getElementName(), compilationUnit); //$NON-NLS-1$ change.setSaveMode(TextFileChange.LEAVE_DIRTY); change.setEdit(edits); change.perform(monitor); } } catch (Exception e) { throw new CoreException(new Status(IStatus.ERROR, PHPUiPlugin.ID, e.toString(), e)); } } }