下面列出了org.eclipse.jface.text.IDocument#addPosition ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Insert tab/spaces at selection offset and each subsequent line origin
*
* @see com.mulgasoft.emacsplus.commands.EmacsPlusCmdHandler#transform(ITextEditor, IDocument, ITextSelection, ExecutionEvent)
*/
@Override
protected int transform(ITextEditor editor, IDocument document, ITextSelection currentSelection, ExecutionEvent event)
throws BadLocationException {
// if we're here, either ^U or no relevant ^I
ColumnSupport cs = new ColumnSupport(document,editor);
String tab = cs.getSpaces(0,cs.getTabWidth());
int off = currentSelection.getOffset();
Position coff = new Position(getCursorOffset(editor,currentSelection),0);
try {
document.addPosition(coff);
int begin = document.getLineOfOffset(off);
int end = document.getLineOfOffset(off+ currentSelection.getLength());
if (begin != end) {
while (++begin <= end) {
document.replace(document.getLineOffset(begin), 0, tab);
}
}
document.replace(off, 0, tab);
} finally {
document.removePosition(coff);
}
return coff.offset;
}
/**
* Positions created for template contexts have to be added to the document so they are updated when the document
* is modified.
*
* @since 2.8
*/
protected Position createPosition(ContentAssistContext context) {
Position position = new Position(context.getReplaceRegion().getOffset(), context.getReplaceRegion().getLength());
IDocument document = context.getDocument();
if (document.containsPositionCategory(XTEXT_TEMPLATE_POS_CATEGORY)) {
try {
document.addPosition(XTEXT_TEMPLATE_POS_CATEGORY, position);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
return position;
}
/**
* Called before document changes occur. It must be followed by a call to postReplace().
*
* @param document the document on which to track the reference position.
* @param offset the offset
* @throws BadLocationException if the offset describes an invalid range in this document
*
*/
public void preReplace(IDocument document, int offset) throws BadLocationException {
fPosition.setOffset(offset);
try {
document.addPositionCategory(CATEGORY);
document.addPositionUpdater(fPositionUpdater);
document.addPosition(CATEGORY, fPosition);
} catch (BadPositionCategoryException e) {
// should not happen
JavaPlugin.log(e);
}
}
/**
* @see com.mulgasoft.emacsplus.commands.EmacsPlusCmdHandler#transform(ITextEditor, IDocument, ITextSelection, ExecutionEvent)
*/
@Override
protected int transform(ITextEditor editor, IDocument document, ITextSelection currentSelection, ExecutionEvent event)
throws BadLocationException {
int result = NO_OFFSET;
Control c = MarkUtils.getTextWidget(editor);
if (c instanceof StyledText) {
StyledText st = (StyledText)c;
String ld = st.getLineDelimiter();
int insertionOffset = getCursorOffset(editor,currentSelection);
int widgetInsertionOffset = st.getCaretOffset();
// the offset position will be updated by the internals on insertion/indent
Position caret= new Position(insertionOffset, 0);
document.addPosition(caret);
st.setSelectionRange(widgetInsertionOffset, 0);
// operate directly on the widget
st.replaceTextRange(widgetInsertionOffset, 0, ld);
document.removePosition(caret);
if (st.getSelection().x == widgetInsertionOffset) {
// move cursor by the amount detected
result = getCursorOffset(editor) + caret.offset - insertionOffset;
}
}
return result;
}
/**
* Really do apply the proposal. Assumed to be run within the prevent flickering mode.
*/
private int doApply(QualifiedName qualifiedName, String alias, IDocument document,
ConfigurableCompletionProposal proposal) throws BadLocationException {
String shortSemanticReplacementString = alias != null ? alias : lastSegmentOrDefaultHost(qualifiedName);
String shortSyntacticReplacementString = valueConverter.toString(shortSemanticReplacementString);
String longReplacementString = shortSyntacticReplacementString
+ ConfigurableCompletionProposalExtensions.getReplacementSuffix(proposal);
ImportRewriter importRewriter = importRewriterFactory.create(document, context);
ReplaceEdit replaceEdit = new ReplaceEdit(
proposal.getReplacementOffset(),
proposal.getReplacementLength(),
longReplacementString);
MultiTextEdit compound = new MultiTextEdit();
AliasLocation aliasLocation = null;
if (alias != null) {
aliasLocation = importRewriter.addSingleImport(qualifiedName, alias, compound);
} else {
importRewriter.addSingleImport(qualifiedName, compound);
}
compound.addChild(replaceEdit);
Position caret = new Position(proposal.getReplacementOffset(), 0);
document.addPosition(caret);
compound.apply(document);
document.removePosition(caret);
int cursorPosition = caret.getOffset();
proposal.setReplacementOffset(cursorPosition - longReplacementString.length());
proposal.setReplacementLength(shortSyntacticReplacementString.length()); // do not include suffix!
proposal.setCursorPosition(
cursorPosition - proposal.getReplacementOffset()); // cursorPosition is relative to replacementOffset!
if (aliasLocation != null) {
final int aliasOffset = aliasLocation.getBaseOffset() + aliasLocation.getRelativeOffset();
final int aliasLength = shortSyntacticReplacementString.length();
N4JSCompletionProposal castedProposal = (N4JSCompletionProposal) proposal;
castedProposal.setLinkedModeBuilder((appliedProposal, currentDocument) -> {
if (viewer.getTextWidget() == null || viewer.getTextWidget().isDisposed()) {
return; // do not attempt to set up linked mode in a disposed UI
}
try {
LinkedPositionGroup group = new LinkedPositionGroup();
group.addPosition(new LinkedPosition(
currentDocument,
aliasOffset,
aliasLength,
LinkedPositionGroup.NO_STOP));
group.addPosition(new LinkedPosition(
currentDocument,
proposal.getReplacementOffset(),
proposal.getReplacementLength(),
LinkedPositionGroup.NO_STOP));
proposal.setSelectionStart(proposal.getReplacementOffset());
proposal.setSelectionLength(proposal.getReplacementLength());
LinkedModeModel model = new LinkedModeModel();
model.addGroup(group);
model.forceInstall();
LinkedModeUI ui = new LinkedModeUI(model, viewer);
ui.setExitPolicy(new IdentifierExitPolicy('\n'));
ui.setExitPosition(
viewer,
proposal.getReplacementOffset()
+ proposal.getCursorPosition()
+ ConfigurableCompletionProposalExtensions.getCursorOffset(proposal),
0,
Integer.MAX_VALUE);
ui.setCyclingMode(LinkedModeUI.CYCLE_NEVER);
ui.enter();
} catch (BadLocationException e) {
logger.error(e.getMessage(), e);
}
});
} else {
adjustCursorPositionIfRequested(proposal);
}
return cursorPosition;
}
/**
* Constructor for the position.
*
* For the offset and length for the proof and statement, first obtain the {@link Location} from the syntax tree. For the proof, use
* the location returned by {@link ProofNode#getLocation()}, where the {@link ProofNode} is obtained by {@link TheoremNode#getProof()}.
*
* For initTheoremOffset, use the beginning of the location returned by {@link TheoremNode#getLocation()}.
*
* For the end of the statement, use the end of the location returned by {@link LevelNode#getLocation()}
* for the {@link LevelNode} returned by {@link TheoremNode#getTheorem()}.
*
* To convert from the 4-int {@link Location} to the offset and length, use {@link AdapterFactory#locationToRegion(IDocument, Location)} and
* then use the offset and length for the returned region.
*
* @param initProofOffset initial offset of the proof
* @param initProofLength initial length of the proof
* @param initTheoremOffset initial offset of the theorem or step
* for which this is a proof
* @param initLengthToEndOfStatement initial length from initTheoremOffset to the end of
* the statement of the theorem
* @param annotation {@link ProjectionAnnotation} that should be at this position
* @param document
*/
public TLAProofPosition(int initProofOffset, int initProofLength, int initTheoremOffset,
int initLengthToEndOfStatement, ProjectionAnnotation annotation, IDocument document)
{
/*
* This seems to be a bit of a hack, but I see
* no other way to do it correctly because of
* how eclipse expands folds. In particular, when eclipse
* is asked to expand a fold, it expands all lines between
* the start line and end line, including the start line but
* excluding the end line. It computes start
* and end lines for a fold with offset and length in the following way:
*
* start line: the greatest numbered line with
* first character offset <= offset of fold
*
* end line: the greatest numbered line with
* first character offset <= offset + length of fold
*
* In other words, it takes the offset of the fold and moves it back until it finds the start
* of a line and takes the offset+length of a fold and moves it back until it finds the
* start of a line. It then expands all lines in between and including the start line but excluding
* the end line. See ProjectionViewer.addMasterDocumentRange() to see the exact implementation.
*
* I think this is a silly way of doing things. The interface IProjectionPosition
* allows the position to compute what lines are collapsed using the method
* computeProjectionRegions but does not provide a way for the position to compute
* what lines are expanded. This asymmetry can result in lines being collapsed
* when a fold is collapsed but not re-expanded when the fold is expanded so that
* lines just disappear. This requires being careful about the offset and length
* of the position as well as what regions are collapsed.
*
* The method alignRegion is stolen from the code for Java editor folding. Read the method
* comments to see what it does. It should ensure that the entire proof is revealed
* when expanded.
*/
IRegion region = alignRegion(new Region(initTheoremOffset, initProofOffset + initProofLength
- initTheoremOffset), document);
offset = region.getOffset();
length = region.getLength();
positionOfStatement = new Position(initTheoremOffset, initLengthToEndOfStatement);
positionOfProof = new Position(initProofOffset, initProofLength);
this.annotation = annotation;
// add positions to document so that they are updated on document changes.
try
{
document.addPosition(positionOfProof);
document.addPosition(positionOfStatement);
} catch (BadLocationException e)
{
Activator.getDefault().logError("Error installing positions for proof fold at " + this, e);
}
}
private List<TypedPosition> createRangeMarkers(TemplateVariable[] variables, IDocument document) throws MalformedTreeException, BadLocationException {
Map<ReplaceEdit, String> markerToOriginal= new HashMap<ReplaceEdit, String>();
MultiTextEdit root= new MultiTextEdit(0, document.getLength());
List<TextEdit> edits= new ArrayList<TextEdit>();
boolean hasModifications= false;
for (int i= 0; i != variables.length; i++) {
final TemplateVariable variable= variables[i];
int[] offsets= variable.getOffsets();
String value= variable.getDefaultValue();
if (isWhitespaceVariable(value)) {
// replace whitespace positions with unformattable comments
String placeholder= COMMENT_START + value + COMMENT_END;
for (int j= 0; j != offsets.length; j++) {
ReplaceEdit replace= new ReplaceEdit(offsets[j], value.length(), placeholder);
root.addChild(replace);
hasModifications= true;
markerToOriginal.put(replace, value);
edits.add(replace);
}
} else {
for (int j= 0; j != offsets.length; j++) {
RangeMarker marker= new RangeMarker(offsets[j], value.length());
root.addChild(marker);
edits.add(marker);
}
}
}
if (hasModifications) {
// update the document and convert the replaces to markers
root.apply(document, TextEdit.UPDATE_REGIONS);
}
List<TypedPosition> positions= new ArrayList<TypedPosition>();
for (Iterator<TextEdit> it= edits.iterator(); it.hasNext();) {
TextEdit edit= it.next();
try {
// abuse TypedPosition to piggy back the original contents of the position
final TypedPosition pos= new TypedPosition(edit.getOffset(), edit.getLength(), markerToOriginal.get(edit));
document.addPosition(CATEGORY, pos);
positions.add(pos);
} catch (BadPositionCategoryException x) {
Assert.isTrue(false);
}
}
return positions;
}
/**
* Determine the correct set of lines and delete the whitespace at the end of each of them.
*
* @see com.mulgasoft.emacsplus.commands.EmacsPlusCmdHandler#transform(ITextEditor, IDocument, ITextSelection, ExecutionEvent)
*/
@Override
protected int transform(ITextEditor editor, IDocument document, ITextSelection currentSelection,
ExecutionEvent event) throws BadLocationException {
int result = NO_OFFSET;
int lastLine = 0;
int firstLine = 0;
int maxOffset = Integer.MAX_VALUE;
if (editor.showsHighlightRangeOnly()) {
// if the buffer is narrowed, then operate on precise region
IRegion narrow = editor.getHighlightRange();
int lastOffset = narrow.getOffset() + narrow.getLength();
firstLine = document.getLineOfOffset(narrow.getOffset());
lastLine = document.getLineOfOffset(lastOffset);
IRegion endInfo = document.getLineInformationOfOffset(lastOffset);
if (endInfo.getOffset() != lastOffset) {
// point maxOffset at the last character in the narrowed region
maxOffset = lastOffset -1;
} else {
// back up if we're at the first offset of the last line
lastLine--;
}
} else {
lastLine = document.getNumberOfLines() -1;
}
if (firstLine <= lastLine) {
Position coff = new Position(getCursorOffset(editor,currentSelection),0);
try {
// record the position so we can restore it after any whitespace deletions
document.addPosition(coff);
deleteWhitepace(lastLine,firstLine,maxOffset,document);
} catch (BadLocationException e) {
// shouldn't happen, but alert user if it does
asyncShowMessage(editor,BAD_LOCATION_ERROR,true);
} finally {
result = coff.getOffset();
document.removePosition(coff);
}
}
return result;
}
private List<TypedPosition> createRangeMarkers(TemplateVariable[] variables, IDocument document) throws MalformedTreeException, BadLocationException {
Map<ReplaceEdit, String> markerToOriginal= new HashMap<ReplaceEdit, String>();
MultiTextEdit root= new MultiTextEdit(0, document.getLength());
List<TextEdit> edits= new ArrayList<TextEdit>();
boolean hasModifications= false;
for (int i= 0; i != variables.length; i++) {
final TemplateVariable variable= variables[i];
int[] offsets= variable.getOffsets();
String value= variable.getDefaultValue();
if (isWhitespaceVariable(value)) {
// replace whitespace positions with unformattable comments
String placeholder= COMMENT_START + value + COMMENT_END;
for (int j= 0; j != offsets.length; j++) {
ReplaceEdit replace= new ReplaceEdit(offsets[j], value.length(), placeholder);
root.addChild(replace);
hasModifications= true;
markerToOriginal.put(replace, value);
edits.add(replace);
}
} else {
for (int j= 0; j != offsets.length; j++) {
RangeMarker marker= new RangeMarker(offsets[j], value.length());
root.addChild(marker);
edits.add(marker);
}
}
}
if (hasModifications) {
// update the document and convert the replaces to markers
root.apply(document, TextEdit.UPDATE_REGIONS);
}
List<TypedPosition> positions= new ArrayList<TypedPosition>();
for (Iterator<TextEdit> it= edits.iterator(); it.hasNext();) {
TextEdit edit= it.next();
try {
// abuse TypedPosition to piggy back the original contents of the position
final TypedPosition pos= new TypedPosition(edit.getOffset(), edit.getLength(), markerToOriginal.get(edit));
document.addPosition(CATEGORY, pos);
positions.add(pos);
} catch (BadPositionCategoryException x) {
Assert.isTrue(false);
}
}
return positions;
}