Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[lang][ui] Auto format code on paste.
close #372 Signed-off-by: Stéphane Galland <galland@arakhne.org>
- Loading branch information
1 parent
93a54d4
commit 3a7b121
Showing
7 changed files
with
422 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
eclipse-sarl/plugins/io.sarl.lang.ui/src/io/sarl/lang/ui/editor/DocumentAutoFormatter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
/* | ||
* $Id$ | ||
* | ||
* SARL is an general-purpose agent programming language. | ||
* More details on http://www.sarl.io | ||
* | ||
* Copyright (C) 2014-2016 the original authors or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.sarl.lang.ui.editor; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
|
||
import org.eclipse.jface.text.BadLocationException; | ||
import org.eclipse.jface.text.DocumentEvent; | ||
import org.eclipse.jface.text.IDocumentListener; | ||
import org.eclipse.jface.text.IRegion; | ||
import org.eclipse.jface.text.formatter.IContentFormatter; | ||
import org.eclipse.xtext.ui.editor.model.IXtextDocument; | ||
import org.eclipse.xtext.util.Strings; | ||
import org.eclipse.xtext.xbase.lib.Exceptions; | ||
|
||
/** A service that enables to do auto-formatting when a document changed. | ||
* | ||
* <p>FIXME: Remove if Xtext accept the patch https://github.com/eclipse/xtext-eclipse/pull/63 | ||
* | ||
* @author $Author: sgalland$ | ||
* @version $FullVersion$ | ||
* @mavengroupid $GroupId$ | ||
* @mavenartifactid $ArtifactId$ | ||
*/ | ||
public class DocumentAutoFormatter implements IDocumentAutoFormatter { | ||
|
||
private Collection<RegionFormattingRequest> formattingRequests = Collections.synchronizedList(new ArrayList<>(1)); | ||
|
||
private IDocumentListener autoFormatListener; | ||
|
||
private IXtextDocument document; | ||
|
||
private IContentFormatter contentFormatter; | ||
|
||
@Override | ||
public void bind(IXtextDocument document, IContentFormatter contentFormatter) { | ||
assert document != null; | ||
assert contentFormatter != null; | ||
this.document = document; | ||
this.contentFormatter = contentFormatter; | ||
} | ||
|
||
@Override | ||
public synchronized void beginAutoFormat() { | ||
if (this.document != null && this.autoFormatListener == null) { | ||
this.formattingRequests.clear(); | ||
this.autoFormatListener = new IDocumentListener() { | ||
@Override | ||
public void documentAboutToBeChanged(DocumentEvent event) { | ||
// | ||
} | ||
|
||
@SuppressWarnings("synthetic-access") | ||
@Override | ||
public void documentChanged(DocumentEvent event) { | ||
if (!Strings.isEmpty(event.getText()) | ||
&& event.getDocument() instanceof IXtextDocument) { | ||
DocumentAutoFormatter.this.formattingRequests.add(new RegionFormattingRequest( | ||
(IXtextDocument) event.getDocument(), event.getOffset(), event.getText().length())); | ||
} | ||
} | ||
}; | ||
this.document.addDocumentListener(this.autoFormatListener); | ||
} | ||
} | ||
|
||
@Override | ||
public void endAutoFormat() { | ||
final Collection<RegionFormattingRequest> requests; | ||
synchronized (this) { | ||
requests = this.formattingRequests; | ||
this.formattingRequests = Collections.synchronizedList(new ArrayList<>(1)); | ||
if (this.autoFormatListener != null) { | ||
final IDocumentListener listener = this.autoFormatListener; | ||
this.autoFormatListener = null; | ||
if (this.document != null) { | ||
this.document.removeDocumentListener(listener); | ||
} | ||
} | ||
} | ||
if (this.contentFormatter != null) { | ||
for (final RegionFormattingRequest request : requests) { | ||
formatRegion(request.document, request.offset, request.length); | ||
} | ||
} | ||
} | ||
|
||
/** Called for formatting a region. | ||
* | ||
* @param document the document to format. | ||
* @param offset the offset of the text to format. | ||
* @param length the length of the text. | ||
*/ | ||
protected void formatRegion(IXtextDocument document, int offset, int length) { | ||
try { | ||
final int startRegionOffset = document.getLineInformationOfOffset( | ||
previousSiblingChar(document, offset)).getOffset(); | ||
final IRegion endLine = document.getLineInformationOfOffset(offset + length); | ||
final int endRegionOffset = endLine.getOffset() + endLine.getLength(); | ||
final int regionLength = endRegionOffset - startRegionOffset; | ||
for (final IRegion region : document.computePartitioning(startRegionOffset, regionLength)) { | ||
this.contentFormatter.format(document, region); | ||
} | ||
} catch (BadLocationException exception) { | ||
Exceptions.sneakyThrow(exception); | ||
} | ||
} | ||
|
||
private static int previousSiblingChar(IXtextDocument document, int offset) throws BadLocationException { | ||
int off = offset - 1; | ||
while (off >= 0 && Character.isWhitespace(document.getChar(off))) { | ||
--off; | ||
} | ||
return off; | ||
} | ||
|
||
/** Request for formatting a region. | ||
* @author $Author: sgalland$ | ||
* @version $FullVersion$ | ||
* @mavengroupid $GroupId$ | ||
* @mavenartifactid $ArtifactId$ | ||
*/ | ||
@SuppressWarnings("checkstyle:visibilitymodifier") | ||
private static class RegionFormattingRequest { | ||
|
||
public final IXtextDocument document; | ||
|
||
public final int offset; | ||
|
||
public final int length; | ||
|
||
RegionFormattingRequest(IXtextDocument document, int offset, int length) { | ||
this.document = document; | ||
this.offset = offset; | ||
this.length = length; | ||
} | ||
|
||
} | ||
|
||
} |
61 changes: 61 additions & 0 deletions
61
eclipse-sarl/plugins/io.sarl.lang.ui/src/io/sarl/lang/ui/editor/IDocumentAutoFormatter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* $Id$ | ||
* | ||
* SARL is an general-purpose agent programming language. | ||
* More details on http://www.sarl.io | ||
* | ||
* Copyright (C) 2014-2016 the original authors or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.sarl.lang.ui.editor; | ||
|
||
import com.google.inject.ImplementedBy; | ||
import org.eclipse.jface.text.formatter.IContentFormatter; | ||
import org.eclipse.xtext.ui.editor.model.IXtextDocument; | ||
|
||
/** A service that enables to do auto-formatting when a document changed. | ||
* | ||
* <p>FIXME: Remove if Xtext accept the patch https://github.com/eclipse/xtext-eclipse/pull/63 | ||
* | ||
* @author $Author: sgalland$ | ||
* @version $FullVersion$ | ||
* @mavengroupid $GroupId$ | ||
* @mavenartifactid $ArtifactId$ | ||
*/ | ||
@ImplementedBy(DocumentAutoFormatter.class) | ||
public interface IDocumentAutoFormatter { | ||
|
||
/** Create an instance of document auto formatter. | ||
* | ||
* @param document the Xtext document associated to this auto-formatter. | ||
* @param contentFormatter the formatter of content to be used. | ||
*/ | ||
default void bind(IXtextDocument document, IContentFormatter contentFormatter) { | ||
// | ||
} | ||
|
||
/** Start auto-formating. | ||
*/ | ||
default void beginAutoFormat() { | ||
// | ||
} | ||
|
||
/** End auto-formating. | ||
*/ | ||
default void endAutoFormat() { | ||
// | ||
} | ||
|
||
} |
136 changes: 136 additions & 0 deletions
136
eclipse-sarl/plugins/io.sarl.lang.ui/src/io/sarl/lang/ui/editor/SARLSourceViewer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/* | ||
* $Id$ | ||
* | ||
* SARL is an general-purpose agent programming language. | ||
* More details on http://www.sarl.io | ||
* | ||
* Copyright (C) 2014-2016 the original authors or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package io.sarl.lang.ui.editor; | ||
|
||
import java.lang.reflect.Field; | ||
|
||
import javax.inject.Inject; | ||
|
||
import com.google.inject.MembersInjector; | ||
import com.google.inject.Provider; | ||
import org.eclipse.jface.text.IDocument; | ||
import org.eclipse.jface.text.IRewriteTarget; | ||
import org.eclipse.jface.text.ITextOperationTarget; | ||
import org.eclipse.jface.text.source.IOverviewRuler; | ||
import org.eclipse.jface.text.source.IVerticalRuler; | ||
import org.eclipse.swt.widgets.Composite; | ||
import org.eclipse.xtend.ide.editor.RichStringAwareSourceViewer; | ||
import org.eclipse.xtend.ide.editor.TypedRegionMerger; | ||
import org.eclipse.xtext.ui.editor.XtextSourceViewer; | ||
import org.eclipse.xtext.ui.editor.model.IXtextDocument; | ||
import org.eclipse.xtext.xbase.lib.Exceptions; | ||
|
||
/** Viewer of SARL code. | ||
* | ||
* <p>Based on the Xtend implementation, extended with the auto-formating feature when pasting. | ||
* FIXME: Remove if Xtext accept the patch https://github.com/eclipse/xtext-eclipse/pull/63 | ||
* | ||
* @author $Author: sgalland$ | ||
* @version $FullVersion$ | ||
* @mavengroupid $GroupId$ | ||
* @mavenartifactid $ArtifactId$ | ||
*/ | ||
public class SARLSourceViewer extends RichStringAwareSourceViewer { | ||
|
||
@Inject | ||
private Provider<IDocumentAutoFormatter> autoFormatterProvider; | ||
|
||
/** Constructor. | ||
* | ||
* @param parent the container. | ||
* @param ruler the vertical ruler. | ||
* @param overviewRuler the overview ruler. | ||
* @param showsAnnotationOverview the annotation shower. | ||
* @param styles the styles. | ||
*/ | ||
public SARLSourceViewer(Composite parent, IVerticalRuler ruler, IOverviewRuler overviewRuler, | ||
boolean showsAnnotationOverview, int styles) { | ||
super(parent, ruler, overviewRuler, showsAnnotationOverview, styles); | ||
} | ||
|
||
/** Replies the document auto-formatter. | ||
* | ||
* @return the service. | ||
*/ | ||
public IDocumentAutoFormatter getDocumentAutoFormatter() { | ||
final IDocument document = getDocument(); | ||
if (document instanceof IXtextDocument) { | ||
final IDocumentAutoFormatter formatter = this.autoFormatterProvider.get(); | ||
formatter.bind((IXtextDocument) document, this.fContentFormatter); | ||
return formatter; | ||
} | ||
return new IDocumentAutoFormatter() { | ||
// | ||
}; | ||
} | ||
|
||
@Override | ||
public void doOperation(int operation) { | ||
if (operation == ITextOperationTarget.PASTE) { | ||
final IRewriteTarget target = getRewriteTarget(); | ||
target.beginCompoundChange(); | ||
final IDocumentAutoFormatter formatter = getDocumentAutoFormatter(); | ||
formatter.beginAutoFormat(); | ||
try { | ||
super.doOperation(operation); | ||
} finally { | ||
formatter.endAutoFormat(); | ||
target.endCompoundChange(); | ||
} | ||
} else { | ||
super.doOperation(operation); | ||
} | ||
} | ||
|
||
/** Factory of SARL code viewer. | ||
* | ||
* @author $Author: sgalland$ | ||
* @version $FullVersion$ | ||
* @mavengroupid $GroupId$ | ||
* @mavenartifactid $ArtifactId$ | ||
*/ | ||
public static class Factory implements XtextSourceViewer.Factory { | ||
|
||
@Inject | ||
private TypedRegionMerger merger; | ||
|
||
@Inject | ||
private MembersInjector<SARLSourceViewer> memberInjector; | ||
|
||
@Override | ||
public XtextSourceViewer createSourceViewer(Composite parent, IVerticalRuler ruler, | ||
IOverviewRuler overviewRuler, boolean showsAnnotationOverview, int styles) { | ||
final SARLSourceViewer result = new SARLSourceViewer(parent, ruler, overviewRuler, showsAnnotationOverview, styles); | ||
try { | ||
final Field field = RichStringAwareSourceViewer.class.getDeclaredField("merger"); //$NON-NLS-1$ | ||
field.setAccessible(true); | ||
field.set(result, this.merger); | ||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException exception) { | ||
Exceptions.sneakyThrow(exception); | ||
} | ||
this.memberInjector.injectMembers(result); | ||
return result; | ||
} | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.