private String setup( String text, boolean isDisabled, boolean isStrikeout, Color background, @Nullable TextRange range) { Map<TextRange, ParameterInfoUIContextEx.Flag> flagsMap = new TreeMap<>(TEXT_RANGE_COMPARATOR); if (range != null) flagsMap.put(range, ParameterInfoUIContextEx.Flag.HIGHLIGHT); if (isDisabled) flagsMap.put(TextRange.create(0, text.length()), ParameterInfoUIContextEx.Flag.DISABLE); if (isStrikeout) flagsMap.put(TextRange.create(0, text.length()), ParameterInfoUIContextEx.Flag.STRIKEOUT); return setup(text, flagsMap, background); }
public static FragmentContent fromRangeMarker(RangeMarker rangeMarker, Project project) { Document document = rangeMarker.getDocument(); VirtualFile file = FileDocumentManager.getInstance().getFile(document); FileType type = FileTypeManager.getInstance().getFileTypeByFile(file); return new FragmentContent( new DocumentContent(project, document), TextRange.create(rangeMarker), project, type); }
public void testDocSynchronizerPrefersLineBoundaryChanges() throws Exception { String text = "import java.awt.List;\n" + "[import java.util.ArrayList;\n]" + "import java.util.HashMap;\n" + "import java.util.Map;"; RangeMarker marker = createMarker(text); synchronizer.startTransaction(getProject(), document, psiFile); String newText = StringUtil.replaceSubstring(document.getText(), TextRange.create(marker), ""); synchronizer.replaceString(document, 0, document.getTextLength(), newText); final List<DocumentEvent> events = new ArrayList<DocumentEvent>(); document.addDocumentListener( new DocumentAdapter() { @Override public void documentChanged(DocumentEvent e) { events.add(e); } }); synchronizer.commitTransaction(document); assertEquals(newText, document.getText()); DocumentEvent event = assertOneElement(events); assertEquals( "DocumentEventImpl[myOffset=22, myOldLength=28, myNewLength=0, myOldString='import java.util.ArrayList;\n', myNewString=''].", event.toString()); }
void loadFromEditor(@NotNull Editor editor) { assertDispatchThread(); LOG.assertTrue(!editor.isDisposed()); clear(); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject); documentManager.commitDocument(editor.getDocument()); PsiFile file = documentManager.getPsiFile(editor.getDocument()); SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(myProject); EditorFoldingInfo info = EditorFoldingInfo.get(editor); FoldRegion[] foldRegions = editor.getFoldingModel().getAllFoldRegions(); for (FoldRegion region : foldRegions) { if (!region.isValid()) continue; PsiElement element = info.getPsiElement(region); boolean expanded = region.isExpanded(); boolean collapseByDefault = element != null && FoldingPolicy.isCollapseByDefault(element) && !FoldingUtil.caretInsideRange(editor, TextRange.create(region)); if (collapseByDefault == expanded || element == null) { FoldingInfo fi = new FoldingInfo(region.getPlaceholderText(), expanded); if (element != null) { myPsiElements.add(smartPointerManager.createSmartPsiElementPointer(element, file)); element.putUserData(FOLDING_INFO_KEY, fi); } else if (region.isValid()) { myRangeMarkers.add(region); region.putUserData(FOLDING_INFO_KEY, fi); } } } }
@Nullable private PyType getImplicitlyResolvedType( @NotNull List<Token<PyElementType>> tokens, @NotNull TypeEvalContext context, @NotNull Map<TextRange, PyType> types, @NotNull Map<PyType, TextRange> fullRanges, TextRange firstRange) { PyType type = null; QualifiedName qName = null; while (!tokens.isEmpty()) { final Token<PyElementType> token = tokens.get(0); final String name = token.getText().toString(); qName = qName != null ? qName.append(name) : QualifiedName.fromComponents(name); PsiElement module = new QualifiedNameResolverImpl(qName).fromElement(myAnchor).firstResult(); if (module == null) { break; } if (module instanceof PsiDirectory) { module = PyUtil.getPackageElement((PsiDirectory) module, myAnchor); } if (module instanceof PyTypedElement) { final PyType moduleType = context.getType((PyTypedElement) module); if (moduleType != null) { type = moduleType; types.put(token.getRange(), type); fullRanges.put( type, TextRange.create(firstRange.getStartOffset(), token.getRange().getEndOffset())); } } tokens.remove(0); } return type; }
@Override public void documentChanged(DocumentEvent e) { if (!myTaskFile.isTrackChanges()) { return; } if (myAnswerPlaceholders.isEmpty()) return; if (e instanceof DocumentEventImpl) { DocumentEventImpl event = (DocumentEventImpl) e; Document document = e.getDocument(); int offset = e.getOffset(); int change = event.getNewLength() - event.getOldLength(); for (AnswerPlaceholderWrapper answerPlaceholderWrapper : myAnswerPlaceholders) { int twStart = answerPlaceholderWrapper.getTwStart(); if (twStart > offset) { twStart += change; } int twEnd = answerPlaceholderWrapper.getTwEnd(); if (twEnd >= offset) { twEnd += change; } AnswerPlaceholder answerPlaceholder = answerPlaceholderWrapper.getAnswerPlaceholder(); int line = document.getLineNumber(twStart); int start = twStart - document.getLineStartOffset(line); int length = twEnd - twStart; answerPlaceholder.setLine(line); answerPlaceholder.setStart(start); if (usePossibleAnswerLength) { answerPlaceholder.setPossibleAnswer( document.getText(TextRange.create(twStart, twStart + length))); } else if (myTrackLength) { answerPlaceholder.setLength(length); } } } }
@Override public void visitField(PsiField field) { // There is a possible case that more than one field is declared for the same type like 'int i, // j;'. We want to process only // the first one then. PsiElement fieldPrev = getPreviousNonWsComment(field.getPrevSibling(), 0); if (fieldPrev instanceof PsiJavaToken && ((PsiJavaToken) fieldPrev).getTokenType() == JavaTokenType.COMMA) { return; } // There is a possible case that fields which share the same type declaration are located on // different document lines, e.g.: // int i1, // i2; // We want to consider only the first declaration then but need to expand its range to all // affected lines (up to semicolon). TextRange range = field.getTextRange(); PsiElement child = field.getLastChild(); boolean needSpecialProcessing = true; if (isSemicolon(child)) { needSpecialProcessing = false; } else if (child instanceof PsiComment) { // There is a possible field definition like below: // int f; // my comment. // The comment goes into field PSI here, that's why we need to handle it properly. PsiElement prev = getPreviousNonWsComment(child, range.getStartOffset()); needSpecialProcessing = prev != null && !isSemicolon(prev); } if (needSpecialProcessing) { for (PsiElement e = field.getNextSibling(); e != null; e = e.getNextSibling()) { if (e instanceof PsiWhiteSpace || e instanceof PsiComment) { // Skip white space and comment continue; } else if (e instanceof PsiJavaToken) { if (((PsiJavaToken) e).getTokenType() == JavaTokenType.COMMA) { // Skip comma continue; } else { break; } } else if (e instanceof PsiField) { PsiElement c = e.getLastChild(); if (c != null) { c = getPreviousNonWsComment(c, range.getStartOffset()); } // Stop if current field ends by a semicolon. if (c instanceof PsiErrorElement // Incomplete field without trailing semicolon || (c instanceof PsiJavaToken && ((PsiJavaToken) c).getTokenType() == JavaTokenType.SEMICOLON)) { range = TextRange.create(range.getStartOffset(), c.getTextRange().getEndOffset()); } else { continue; } } break; } } JavaElementArrangementEntry entry = createNewEntry(field, range, FIELD, field.getName(), true); processEntry(entry, field, field.getInitializer()); }
@NotNull public String getText() { RangeHighlighterEx highlighter = this.highlighter; if (highlighter == null) throw new RuntimeException("info not applied yet"); if (!highlighter.isValid()) return ""; return highlighter.getDocument().getText(TextRange.create(highlighter)); }
protected static List<TextRange> getSelectedRanges(@NotNull SelectionModel selectionModel) { final List<TextRange> ranges = new SmartList<TextRange>(); if (selectionModel.hasSelection()) { TextRange range = TextRange.create(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); ranges.add(range); } else if (selectionModel.hasBlockSelection()) { int[] starts = selectionModel.getBlockSelectionStarts(); int[] ends = selectionModel.getBlockSelectionEnds(); for (int i = 0; i < starts.length; i++) { ranges.add(TextRange.create(starts[i], ends[i])); } } return ranges; }
static TextRange processDocument( Document document, RangeMarker marker, Commenter commenter, boolean escape) { if (commenter instanceof EscapingCommenter) { if (escape) { ((EscapingCommenter) commenter).escape(document, marker); } else { ((EscapingCommenter) commenter).unescape(document, marker); } } return TextRange.create(marker.getStartOffset(), marker.getEndOffset()); }
public boolean changesRange(TextRange range) { if (myAltFullRange != null) { return range.intersects(myAltFullRange.getStartOffset(), myAltFullRange.getEndOffset()); } else if (!myMarkers.isEmpty()) { TextRange hostRange = TextRange.create( myMarkers.get(0).first.getStartOffset(), myMarkers.get(myMarkers.size() - 1).first.getEndOffset()); return range.intersects(hostRange); } return false; }
public void _testRandomAddRemove() { int N = 100; for (int ti = 0; ; ti++) { if (ti % 10000 == 0) System.out.println(ti); DocumentEx document = (DocumentEx) EditorFactory.getInstance().createDocument(StringUtil.repeatSymbol(' ', N)); Random gen = new Random(); List<Pair<RangeMarker, TextRange>> adds = new ArrayList<Pair<RangeMarker, TextRange>>(); List<Pair<RangeMarker, TextRange>> dels = new ArrayList<Pair<RangeMarker, TextRange>>(); try { for (int i = 0; i < 30; i++) { int x = gen.nextInt(N); int y = x + gen.nextInt(N - x); if (gen.nextBoolean()) { x = 0; y = document.getTextLength(); } RangeMarkerEx r = (RangeMarkerEx) document.createRangeMarker(x, y); adds.add(Pair.create((RangeMarker) r, TextRange.create(r))); } List<Pair<RangeMarker, TextRange>> candidates = new ArrayList<Pair<RangeMarker, TextRange>>(adds); while (!candidates.isEmpty()) { int size = candidates.size(); int x = gen.nextInt(size); Pair<RangeMarker, TextRange> c = candidates.remove(x); RangeMarkerEx r = (RangeMarkerEx) c.first; assertEquals(size - 1, candidates.size()); dels.add(c); r.dispose(); } } catch (AssertionError e) { String s = "adds: "; for (Pair<RangeMarker, TextRange> c : adds) { TextRange t = c.second; s += t.getStartOffset() + "," + t.getEndOffset() + ", "; } s += "\ndels: "; for (Pair<RangeMarker, TextRange> c : dels) { int index = adds.indexOf(c); assertSame(c, adds.get(index)); s += index + ", "; } System.err.println(s); throw e; } } }
private boolean isWhiteSpaceOrComment(@NotNull PsiElement element, @NotNull TextRange range) { final TextRange textRange = element.getTextRange(); TextRange intersection = range.intersection(textRange); if (intersection == null) { return false; } intersection = TextRange.create( Math.max(intersection.getStartOffset() - textRange.getStartOffset(), 0), Math.min( intersection.getEndOffset() - textRange.getStartOffset(), textRange.getLength())); return isWhiteSpaceOrComment(element) || intersection.substring(element.getText()).trim().length() == 0; }
@NotNull private static RangeMarker combineScopes( RangeMarker old, @NotNull TextRange scope, int textLength, @NotNull Document document) { if (old == null) { if (scope.equalsToRange(0, textLength)) return WHOLE_FILE_DIRTY_MARKER; return document.createRangeMarker(scope); } if (old == WHOLE_FILE_DIRTY_MARKER) return old; TextRange oldRange = TextRange.create(old); TextRange union = scope.union(oldRange); if (old.isValid() && union.equals(oldRange)) { return old; } if (union.getEndOffset() > textLength) { union = union.intersection(new TextRange(0, textLength)); } assert union != null; return document.createRangeMarker(union); }
private static List<Token<PyElementType>> tokenize(@NotNull String s) { final List<Token<PyElementType>> tokens = new ArrayList<>(); final _PyTypeLexer lexer = new _PyTypeLexer(new StringReader(s)); lexer.reset(s, 0, s.length(), lexer.yystate()); try { PyElementType type; while ((type = lexer.advance()) != null) { if (type == PyTypeTokenTypes.SPACE || type == PyTypeTokenTypes.MARKUP) { continue; } final TextRange range = TextRange.create(lexer.getTokenStart(), lexer.getTokenEnd()); final Token<PyElementType> token = new Token<>(type, lexer.yytext(), range); tokens.add(token); } } catch (IOException e) { return Collections.emptyList(); } catch (Error e) { return Collections.emptyList(); } return tokens; }
/** * @return null for processed file, whole file for untouched or entirely dirty file, range(usually * code block) for dirty region (optimization) */ @Nullable public TextRange getFileDirtyScope(@NotNull Document document, int passId) { synchronized (myDocumentToStatusMap) { PsiFile file = PsiDocumentManager.getInstance(myProject).getPsiFile(document); if (!ProblemHighlightFilter.shouldHighlightFile(file)) return null; FileStatus status = myDocumentToStatusMap.get(document); if (status == null) { return file == null ? null : file.getTextRange(); } if (status.defensivelyMarked) { status.markWholeFileDirty(myProject); status.defensivelyMarked = false; } LOG.assertTrue(status.dirtyScopes.containsKey(passId), "Unknown pass " + passId); RangeMarker marker = status.dirtyScopes.get(passId); return marker == null ? null : marker.isValid() ? TextRange.create(marker) : new TextRange(0, document.getTextLength()); } }
public static boolean hasTemplatePrefix(LookupImpl lookup, char shortcutChar) { lookup.refreshUi(false, false); // to bring the list model up to date CompletionProcess completion = CompletionService.getCompletionService().getCurrentCompletion(); if (completion == null || !completion.isAutopopupCompletion()) { return false; } if (lookup.isSelectionTouched()) { return false; } final PsiFile file = lookup.getPsiFile(); if (file == null) return false; final Editor editor = lookup.getEditor(); PsiDocumentManager.getInstance(file.getProject()).commitDocument(editor.getDocument()); final int end = editor.getCaretModel().getOffset(); final int start = lookup.getLookupStart(); final String prefix = !lookup.getItems().isEmpty() ? editor.getDocument().getText(TextRange.create(start, end)) : ListTemplatesHandler.getPrefix(editor.getDocument(), end); if (TemplateSettings.getInstance().getTemplates(prefix).isEmpty()) { return false; } for (TemplateImpl template : SurroundWithTemplateHandler.getApplicableTemplates(editor, file, false)) { if (prefix.equals(template.getKey()) && shortcutChar == TemplateSettings.getInstance().getShortcutChar(template)) { return true; } } return false; }
public ASTNode processRange(final ASTNode element, final int startOffset, final int endOffset) { final PsiElement psiElement = SourceTreeToPsiMap.treeElementToPsi(element); assert psiElement != null; final PsiFile file = psiElement.getContainingFile(); final Document document = file.getViewProvider().getDocument(); final RangeMarker rangeMarker = document != null && endOffset < document.getTextLength() ? document.createRangeMarker(startOffset, endOffset) : null; PsiElement elementToFormat = document instanceof DocumentWindow ? InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file) : psiElement; final PsiFile fileToFormat = elementToFormat.getContainingFile(); final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(fileToFormat); if (builder != null) { TextRange range = preprocess(element, TextRange.create(startOffset, endOffset)); if (document instanceof DocumentWindow) { DocumentWindow documentWindow = (DocumentWindow) document; range = documentWindow.injectedToHost(range); } // final SmartPsiElementPointer pointer = // SmartPointerManager.getInstance(psiElement.getProject()).createSmartPsiElementPointer(psiElement); final FormattingModel model = CoreFormatterUtil.buildModel( builder, elementToFormat, mySettings, FormattingMode.REFORMAT); if (file.getTextLength() > 0) { try { FormatterEx.getInstanceEx() .format( model, mySettings, mySettings.getIndentOptions(fileToFormat.getFileType()), new FormatTextRanges(range, true)); wrapLongLinesIfNecessary(file, document, startOffset, endOffset); } catch (IncorrectOperationException e) { LOG.error(e); } } if (!psiElement.isValid()) { if (rangeMarker != null) { final PsiElement at = file.findElementAt(rangeMarker.getStartOffset()); final PsiElement result = PsiTreeUtil.getParentOfType(at, psiElement.getClass(), false); assert result != null; rangeMarker.dispose(); return result.getNode(); } else { assert false; } } // return SourceTreeToPsiMap.psiElementToTree(pointer.getElement()); } if (rangeMarker != null) { rangeMarker.dispose(); } return element; }
private static TextRange preprocess(@NotNull final ASTNode node, @NotNull TextRange range) { TextRange result = range; PsiElement psi = node.getPsi(); if (!psi.isValid()) { for (PreFormatProcessor processor : Extensions.getExtensions(PreFormatProcessor.EP_NAME)) { result = processor.process(node, result); } return result; } PsiFile file = psi.getContainingFile(); // We use a set here because we encountered a situation when more than one PSI leaf points to // the same injected fragment // (at least for sql injected into sql). final LinkedHashSet<TextRange> injectedFileRangesSet = ContainerUtilRt.newLinkedHashSet(); if (!psi.getProject().isDefault()) { List<DocumentWindow> injectedDocuments = InjectedLanguageUtil.getCachedInjectedDocuments(file); if (!injectedDocuments.isEmpty()) { for (DocumentWindow injectedDocument : injectedDocuments) { injectedFileRangesSet.add( TextRange.from(injectedDocument.injectedToHost(0), injectedDocument.getTextLength())); } } else { Collection<PsiLanguageInjectionHost> injectionHosts = collectInjectionHosts(file, range); PsiLanguageInjectionHost.InjectedPsiVisitor visitor = new PsiLanguageInjectionHost.InjectedPsiVisitor() { @Override public void visit( @NotNull PsiFile injectedPsi, @NotNull List<PsiLanguageInjectionHost.Shred> places) { for (PsiLanguageInjectionHost.Shred place : places) { Segment rangeMarker = place.getHostRangeMarker(); injectedFileRangesSet.add( TextRange.create(rangeMarker.getStartOffset(), rangeMarker.getEndOffset())); } } }; for (PsiLanguageInjectionHost host : injectionHosts) { InjectedLanguageUtil.enumerate(host, visitor); } } } if (!injectedFileRangesSet.isEmpty()) { List<TextRange> ranges = ContainerUtilRt.newArrayList(injectedFileRangesSet); Collections.reverse(ranges); for (TextRange injectedFileRange : ranges) { int startHostOffset = injectedFileRange.getStartOffset(); int endHostOffset = injectedFileRange.getEndOffset(); if (startHostOffset >= range.getStartOffset() && endHostOffset <= range.getEndOffset()) { PsiFile injected = InjectedLanguageUtil.findInjectedPsiNoCommit(file, startHostOffset); if (injected != null) { int startInjectedOffset = range.getStartOffset() > startHostOffset ? startHostOffset - range.getStartOffset() : 0; int endInjectedOffset = injected.getTextLength(); if (range.getEndOffset() < endHostOffset) { endInjectedOffset -= endHostOffset - range.getEndOffset(); } final TextRange initialInjectedRange = TextRange.create(startInjectedOffset, endInjectedOffset); TextRange injectedRange = initialInjectedRange; for (PreFormatProcessor processor : Extensions.getExtensions(PreFormatProcessor.EP_NAME)) { injectedRange = processor.process(injected.getNode(), injectedRange); } // Allow only range expansion (not reduction) for injected context. if ((initialInjectedRange.getStartOffset() > injectedRange.getStartOffset() && initialInjectedRange.getStartOffset() > 0) || (initialInjectedRange.getEndOffset() < injectedRange.getEndOffset() && initialInjectedRange.getEndOffset() < injected.getTextLength())) { range = TextRange.create( range.getStartOffset() + injectedRange.getStartOffset() - initialInjectedRange.getStartOffset(), range.getEndOffset() + initialInjectedRange.getEndOffset() - injectedRange.getEndOffset()); } } } } } for (PreFormatProcessor processor : Extensions.getExtensions(PreFormatProcessor.EP_NAME)) { result = processor.process(node, result); } return result; }
public void processText( PsiFile file, final FormatTextRanges ranges, boolean doPostponedFormatting) { final Project project = file.getProject(); Document document = PsiDocumentManager.getInstance(project).getDocument(file); final List<FormatTextRanges.FormatTextRange> textRanges = ranges.getRanges(); if (document instanceof DocumentWindow) { file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(file); final DocumentWindow documentWindow = (DocumentWindow) document; for (FormatTextRanges.FormatTextRange range : textRanges) { range.setTextRange(documentWindow.injectedToHost(range.getTextRange())); } document = documentWindow.getDelegate(); } final FormattingModelBuilder builder = LanguageFormatting.INSTANCE.forContext(file); if (builder != null) { if (file.getTextLength() > 0) { try { final PsiElement startElement = file.findElementAt(textRanges.get(0).getTextRange().getStartOffset()); final PsiElement endElement = file.findElementAt( textRanges.get(textRanges.size() - 1).getTextRange().getEndOffset() - 1); final PsiElement commonParent = startElement != null && endElement != null ? PsiTreeUtil.findCommonParent(startElement, endElement) : null; ASTNode node = null; if (commonParent != null) { node = commonParent.getNode(); } if (node == null) { node = file.getNode(); } for (FormatTextRanges.FormatTextRange range : ranges.getRanges()) { TextRange rangeToUse = preprocess(node, range.getTextRange()); range.setTextRange(rangeToUse); } if (doPostponedFormatting) { RangeMarker[] markers = new RangeMarker[textRanges.size()]; int i = 0; for (FormatTextRanges.FormatTextRange range : textRanges) { TextRange textRange = range.getTextRange(); int start = textRange.getStartOffset(); int end = textRange.getEndOffset(); if (start >= 0 && end > start && end <= document.getTextLength()) { markers[i] = document.createRangeMarker(textRange); markers[i].setGreedyToLeft(true); markers[i].setGreedyToRight(true); i++; } } final PostprocessReformattingAspect component = file.getProject().getComponent(PostprocessReformattingAspect.class); FormattingProgressTask.FORMATTING_CANCELLED_FLAG.set(false); component.doPostponedFormatting(file.getViewProvider()); i = 0; for (FormatTextRanges.FormatTextRange range : textRanges) { RangeMarker marker = markers[i]; if (marker != null) { range.setTextRange(TextRange.create(marker)); marker.dispose(); } i++; } } if (FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get()) { return; } final FormattingModel originalModel = CoreFormatterUtil.buildModel(builder, file, mySettings, FormattingMode.REFORMAT); final FormattingModel model = new DocumentBasedFormattingModel( originalModel.getRootBlock(), document, project, mySettings, file.getFileType(), file); FormatterEx formatter = FormatterEx.getInstanceEx(); if (CodeStyleManager.getInstance(project).isSequentialProcessingAllowed()) { formatter.setProgressTask(new FormattingProgressTask(project, file, document)); } CommonCodeStyleSettings.IndentOptions indentOptions = null; if (builder instanceof FormattingModelBuilderEx) { indentOptions = ((FormattingModelBuilderEx) builder) .getIndentOptionsToUse(file, ranges, mySettings); } if (indentOptions == null) { indentOptions = mySettings.getIndentOptions(file.getFileType()); } formatter.format(model, mySettings, indentOptions, ranges); for (FormatTextRanges.FormatTextRange range : textRanges) { TextRange textRange = range.getTextRange(); wrapLongLinesIfNecessary( file, document, textRange.getStartOffset(), textRange.getEndOffset()); } } catch (IncorrectOperationException e) { LOG.error(e); } } } }
private void dumpEditorMarkupAndSelection(PrintStream dumpStream) { dumpStream.println(mySearchResults.getFindModel()); if (myReplacementPreviewText != null) { dumpStream.println("--"); dumpStream.println("Replacement Preview: " + myReplacementPreviewText); } dumpStream.println("--"); Editor editor = mySearchResults.getEditor(); RangeHighlighter[] highlighters = editor.getMarkupModel().getAllHighlighters(); List<Pair<Integer, Character>> ranges = new ArrayList<Pair<Integer, Character>>(); for (RangeHighlighter highlighter : highlighters) { ranges.add(new Pair<Integer, Character>(highlighter.getStartOffset(), '[')); ranges.add(new Pair<Integer, Character>(highlighter.getEndOffset(), ']')); } SelectionModel selectionModel = editor.getSelectionModel(); if (selectionModel.getSelectionStart() != selectionModel.getSelectionEnd()) { ranges.add(new Pair<Integer, Character>(selectionModel.getSelectionStart(), '<')); ranges.add(new Pair<Integer, Character>(selectionModel.getSelectionEnd(), '>')); } ranges.add(new Pair<Integer, Character>(-1, '\n')); ranges.add(new Pair<Integer, Character>(editor.getDocument().getTextLength() + 1, '\n')); ContainerUtil.sort( ranges, new Comparator<Pair<Integer, Character>>() { @Override public int compare(Pair<Integer, Character> pair, Pair<Integer, Character> pair2) { int res = pair.first - pair2.first; if (res == 0) { Character c1 = pair.second; Character c2 = pair2.second; if (c1 == '<' && c2 == '[') { return 1; } else if (c1 == '[' && c2 == '<') { return -1; } return c1.compareTo(c2); } return res; } }); Document document = editor.getDocument(); for (int i = 0; i < ranges.size() - 1; ++i) { Pair<Integer, Character> pair = ranges.get(i); Pair<Integer, Character> pair1 = ranges.get(i + 1); dumpStream.print( pair.second + document.getText( TextRange.create( Math.max(pair.first, 0), Math.min(pair1.first, document.getTextLength())))); } dumpStream.println("\n--"); if (NotFound) { dumpStream.println("Not Found"); dumpStream.println("--"); NotFound = false; } for (RangeHighlighter highlighter : highlighters) { dumpStream.println(highlighter + " : " + highlighter.getTextAttributes()); } dumpStream.println("------------"); }
public String setup( final String[] texts, Function<String, String> escapeFunction, final EnumSet<ParameterInfoUIContextEx.Flag>[] flags, final Color background) { StringBuilder buf = new StringBuilder(); removeAll(); setBackground(background); int index = 0; int curOffset = 0; final ArrayList<OneLineComponent> components = new ArrayList<>(); Map<TextRange, ParameterInfoUIContextEx.Flag> flagsMap = new TreeMap<>(TEXT_RANGE_COMPARATOR); String line = ""; for (int i = 0; i < texts.length; i++) { String paramText = escapeString(texts[i], escapeFunction); if (paramText == null) break; line += texts[i]; final EnumSet<ParameterInfoUIContextEx.Flag> flag = flags[i]; if (flag.contains(ParameterInfoUIContextEx.Flag.HIGHLIGHT)) { flagsMap.put( TextRange.create(curOffset, curOffset + paramText.trim().length()), ParameterInfoUIContextEx.Flag.HIGHLIGHT); } if (flag.contains(ParameterInfoUIContextEx.Flag.DISABLE)) { flagsMap.put( TextRange.create(curOffset, curOffset + paramText.trim().length()), ParameterInfoUIContextEx.Flag.DISABLE); } if (flag.contains(ParameterInfoUIContextEx.Flag.STRIKEOUT)) { flagsMap.put( TextRange.create(curOffset, curOffset + paramText.trim().length()), ParameterInfoUIContextEx.Flag.STRIKEOUT); } curOffset += paramText.length(); if (line.length() >= 50) { final OneLineComponent component = new OneLineComponent(); buf.append(component.setup(escapeString(line, escapeFunction), flagsMap, background)); add( component, new GridBagConstraints( 0, index, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); index += 1; flagsMap.clear(); curOffset = 0; line = ""; components.add(component); } } final OneLineComponent component = new OneLineComponent(); buf.append(component.setup(escapeString(line, escapeFunction), flagsMap, background)); add( component, new GridBagConstraints( 0, index, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); components.add(component); myOneLineComponents = components.toArray(new OneLineComponent[components.size()]); return buf.toString(); }
@Nullable @Override public ParseResult fun(@NotNull Pair<Token<PyElementType>, List<Token<PyElementType>>> value) { final Token<PyElementType> first = value.getFirst(); final List<Token<PyElementType>> rest = value.getSecond(); final TextRange firstRange = first.getRange(); final boolean unqualified = rest.isEmpty(); if (unqualified) { final ParseResult result = parseBuiltinType(first); if (result != null) { return result; } } final PsiFile file = myAnchor.getContainingFile(); final List<Token<PyElementType>> tokens = new ArrayList<>(); tokens.add(first); tokens.addAll(rest); if (file instanceof PyFile) { final PyFile pyFile = (PyFile) file; final TypeEvalContext context = TypeEvalContext.codeInsightFallback(file.getProject()); final Map<TextRange, PyType> types = new HashMap<>(); final Map<PyType, TextRange> fullRanges = new HashMap<>(); final Map<PyType, PyImportElement> imports = new HashMap<>(); PyType type = resolveQualifierType(tokens, pyFile, context, types, fullRanges, imports); PsiElement resolved = type != null ? getElement(type) : null; if (type != null) { final PyResolveContext resolveContext = PyResolveContext.defaultContext().withTypeEvalContext(context); final PyExpression expression = myAnchor instanceof PyExpression ? (PyExpression) myAnchor : null; for (Token<PyElementType> token : tokens) { final PyType qualifierType = type; type = null; final List<? extends RatedResolveResult> results = qualifierType.resolveMember( token.getText().toString(), expression, AccessDirection.READ, resolveContext); if (results != null && !results.isEmpty()) { resolved = results.get(0).getElement(); if (resolved instanceof PyTypedElement) { type = context.getType((PyTypedElement) resolved); if (type != null && !allowResolveToType(type)) { type = null; break; } if (type instanceof PyClassLikeType) { type = ((PyClassLikeType) type).toInstance(); } } } if (type == null) { break; } types.put(token.getRange(), type); fullRanges.put( type, TextRange.create(firstRange.getStartOffset(), token.getRange().getEndOffset())); } if (type != null) { return new ParseResult(resolved, type, types, fullRanges, imports); } } } return EMPTY_RESULT; }
public String setup( final String[] texts, final EnumSet<ParameterInfoUIContextEx.Flag>[] flags, final Color background) { StringBuilder buf = new StringBuilder(); removeAll(); final String[] lines = UIUtil.splitText(StringUtil.join(texts), getFontMetrics(BOLD_FONT), myWidthLimit, ','); int index = 0; int curOffset = 0; myOneLineComponents = new OneLineComponent[lines.length]; Map<TextRange, ParameterInfoUIContextEx.Flag> flagsMap = new TreeMap<TextRange, ParameterInfoUIContextEx.Flag>(TEXT_RANGE_COMPARATOR); int added = 0; for (int i = 0; i < texts.length; i++) { String line = escapeString(texts[i]); if (lines.length <= index) break; String text = lines[index]; final int paramCount = StringUtil.split(text, ", ").size(); final EnumSet<ParameterInfoUIContextEx.Flag> flag = flags[i]; if (flag.contains(ParameterInfoUIContextEx.Flag.HIGHLIGHT)) { flagsMap.put( TextRange.create(curOffset, curOffset + line.trim().length()), ParameterInfoUIContextEx.Flag.HIGHLIGHT); } if (flag.contains(ParameterInfoUIContextEx.Flag.DISABLE)) { flagsMap.put( TextRange.create(curOffset, curOffset + line.trim().length()), ParameterInfoUIContextEx.Flag.DISABLE); } if (flag.contains(ParameterInfoUIContextEx.Flag.STRIKEOUT)) { flagsMap.put( TextRange.create(curOffset, curOffset + line.trim().length()), ParameterInfoUIContextEx.Flag.STRIKEOUT); } curOffset += line.length(); if (i == paramCount + added - 1) { myOneLineComponents[index] = new OneLineComponent(); setBackground(background); buf.append(myOneLineComponents[index].setup(escapeString(text), flagsMap, background)); add( myOneLineComponents[index], new GridBagConstraints( 0, index, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); index += 1; flagsMap.clear(); curOffset = 1; added += paramCount; } } return buf.toString(); }
public void performAction(IntroduceOperation operation) { final PsiFile file = operation.getFile(); if (!CommonRefactoringUtil.checkReadOnlyStatus(file)) { return; } final Editor editor = operation.getEditor(); if (editor.getSettings().isVariableInplaceRenameEnabled()) { final TemplateState templateState = TemplateManagerImpl.getTemplateState(operation.getEditor()); if (templateState != null && !templateState.isFinished()) { return; } } PsiElement element1 = null; PsiElement element2 = null; final SelectionModel selectionModel = editor.getSelectionModel(); boolean singleElementSelection = false; if (selectionModel.hasSelection()) { element1 = file.findElementAt(selectionModel.getSelectionStart()); element2 = file.findElementAt(selectionModel.getSelectionEnd() - 1); if (element1 instanceof PsiWhiteSpace) { int startOffset = element1.getTextRange().getEndOffset(); element1 = file.findElementAt(startOffset); } if (element2 instanceof PsiWhiteSpace) { int endOffset = element2.getTextRange().getStartOffset(); element2 = file.findElementAt(endOffset - 1); } if (element1 == element2) { singleElementSelection = true; } } else { if (smartIntroduce(operation)) { return; } final CaretModel caretModel = editor.getCaretModel(); final Document document = editor.getDocument(); int lineNumber = document.getLineNumber(caretModel.getOffset()); if ((lineNumber >= 0) && (lineNumber < document.getLineCount())) { element1 = file.findElementAt(document.getLineStartOffset(lineNumber)); element2 = file.findElementAt(document.getLineEndOffset(lineNumber) - 1); } } final Project project = operation.getProject(); if (element1 == null || element2 == null) { showCannotPerformError(project, editor); return; } element1 = PyRefactoringUtil.getSelectedExpression(project, file, element1, element2); if (element1 == null) { showCannotPerformError(project, editor); return; } if (singleElementSelection && element1 instanceof PyStringLiteralExpression) { final PyStringLiteralExpression literal = (PyStringLiteralExpression) element1; // Currently introduce for substrings of a multi-part string literals is not supported if (literal.getStringNodes().size() > 1) { showCannotPerformError(project, editor); return; } final int offset = element1.getTextOffset(); final TextRange selectionRange = TextRange.create(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd()); final TextRange elementRange = element1.getTextRange(); if (!elementRange.equals(selectionRange) && elementRange.contains(selectionRange)) { final TextRange innerRange = literal.getStringValueTextRange(); final TextRange intersection = selectionRange.shiftRight(-offset).intersection(innerRange); final TextRange finalRange = intersection != null ? intersection : selectionRange; final String text = literal.getText(); if (getFormatValueExpression(literal) != null && breaksStringFormatting(text, finalRange) || getNewStyleFormatValueExpression(literal) != null && breaksNewStyleStringFormatting(text, finalRange) || breaksStringEscaping(text, finalRange)) { showCannotPerformError(project, editor); return; } element1.putUserData( PyReplaceExpressionUtil.SELECTION_BREAKS_AST_NODE, Pair.create(element1, finalRange)); } } if (!checkIntroduceContext(file, editor, element1)) { return; } operation.setElement(element1); performActionOnElement(operation); }
private static void doPaste( final Editor editor, final Project project, final PsiFile file, final Document document, final Producer<Transferable> producer) { Transferable content = null; if (producer != null) { content = producer.produce(); } else { CopyPasteManager manager = CopyPasteManager.getInstance(); if (manager.areDataFlavorsAvailable(DataFlavor.stringFlavor)) { content = manager.getContents(); if (content != null) { manager.stopKillRings(); } } } if (content != null) { String text = null; try { text = (String) content.getTransferData(DataFlavor.stringFlavor); } catch (Exception e) { editor.getComponent().getToolkit().beep(); } if (text == null) return; final CodeInsightSettings settings = CodeInsightSettings.getInstance(); final Map<CopyPastePostProcessor, TextBlockTransferableData> extraData = new HashMap<CopyPastePostProcessor, TextBlockTransferableData>(); for (CopyPastePostProcessor processor : Extensions.getExtensions(CopyPastePostProcessor.EP_NAME)) { TextBlockTransferableData data = processor.extractTransferableData(content); if (data != null) { extraData.put(processor, data); } } text = TextBlockTransferable.convertLineSeparators(text, "\n", extraData.values()); final CaretModel caretModel = editor.getCaretModel(); final SelectionModel selectionModel = editor.getSelectionModel(); final int col = caretModel.getLogicalPosition().column; // There is a possible case that we want to perform paste while there is an active selection // at the editor and caret is located // inside it (e.g. Ctrl+A is pressed while caret is not at the zero column). We want to insert // the text at selection start column // then, hence, inserted block of text should be indented according to the selection start as // well. final int blockIndentAnchorColumn; final int caretOffset = caretModel.getOffset(); if (selectionModel.hasSelection() && caretOffset >= selectionModel.getSelectionStart()) { blockIndentAnchorColumn = editor.offsetToLogicalPosition(selectionModel.getSelectionStart()).column; } else { blockIndentAnchorColumn = col; } // We assume that EditorModificationUtil.insertStringAtCaret() is smart enough to remove // currently selected text (if any). RawText rawText = RawText.fromTransferable(content); String newText = text; for (CopyPastePreProcessor preProcessor : Extensions.getExtensions(CopyPastePreProcessor.EP_NAME)) { newText = preProcessor.preprocessOnPaste(project, file, editor, newText, rawText); } int indentOptions = text.equals(newText) ? settings.REFORMAT_ON_PASTE : CodeInsightSettings.REFORMAT_BLOCK; text = newText; if (LanguageFormatting.INSTANCE.forContext(file) == null && indentOptions != CodeInsightSettings.NO_REFORMAT) { indentOptions = CodeInsightSettings.INDENT_BLOCK; } final String _text = text; ApplicationManager.getApplication() .runWriteAction( new Runnable() { @Override public void run() { EditorModificationUtil.insertStringAtCaret(editor, _text, false, true); } }); int length = text.length(); int offset = caretModel.getOffset() - length; if (offset < 0) { length += offset; offset = 0; } final RangeMarker bounds = document.createRangeMarker(offset, offset + length); caretModel.moveToOffset(bounds.getEndOffset()); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); selectionModel.removeSelection(); final Ref<Boolean> indented = new Ref<Boolean>(Boolean.FALSE); for (Map.Entry<CopyPastePostProcessor, TextBlockTransferableData> e : extraData.entrySet()) { //noinspection unchecked e.getKey() .processTransferableData(project, editor, bounds, caretOffset, indented, e.getValue()); } boolean pastedTextContainsWhiteSpacesOnly = CharArrayUtil.shiftForward(document.getCharsSequence(), bounds.getStartOffset(), " \n\t") >= bounds.getEndOffset(); VirtualFile virtualFile = file.getVirtualFile(); if (!pastedTextContainsWhiteSpacesOnly && (virtualFile == null || !SingleRootFileViewProvider.isTooLargeForIntelligence(virtualFile))) { final int indentOptions1 = indentOptions; ApplicationManager.getApplication() .runWriteAction( new Runnable() { @Override public void run() { switch (indentOptions1) { case CodeInsightSettings.INDENT_BLOCK: if (!indented.get()) { indentBlock( project, editor, bounds.getStartOffset(), bounds.getEndOffset(), blockIndentAnchorColumn); } break; case CodeInsightSettings.INDENT_EACH_LINE: if (!indented.get()) { indentEachLine( project, editor, bounds.getStartOffset(), bounds.getEndOffset()); } break; case CodeInsightSettings.REFORMAT_BLOCK: indentEachLine( project, editor, bounds.getStartOffset(), bounds .getEndOffset()); // this is needed for example when inserting a // comment before method reformatBlock( project, editor, bounds.getStartOffset(), bounds.getEndOffset()); break; } } }); } if (bounds.isValid()) { caretModel.moveToOffset(bounds.getEndOffset()); editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); selectionModel.removeSelection(); editor.putUserData(EditorEx.LAST_PASTED_REGION, TextRange.create(bounds)); } } }
private List<PostponedAction> normalizeAndReorderPostponedActions( final TreeSet<PostprocessFormattingTask> rangesToProcess, Document document) { final List<PostprocessFormattingTask> freeFormatingActions = new ArrayList<PostprocessFormattingTask>(); final List<ReindentTask> indentActions = new ArrayList<ReindentTask>(); PostprocessFormattingTask accumulatedTask = null; Iterator<PostprocessFormattingTask> iterator = rangesToProcess.iterator(); while (iterator.hasNext()) { final PostprocessFormattingTask currentTask = iterator.next(); if (accumulatedTask == null) { accumulatedTask = currentTask; iterator.remove(); } else if (accumulatedTask.getStartOffset() > currentTask.getEndOffset() || accumulatedTask.getStartOffset() == currentTask.getEndOffset() && !canStickActionsTogether(accumulatedTask, currentTask)) { // action can be pushed if (accumulatedTask instanceof ReindentTask) { indentActions.add((ReindentTask) accumulatedTask); } else { freeFormatingActions.add(accumulatedTask); } accumulatedTask = currentTask; iterator.remove(); } else if (accumulatedTask instanceof ReformatTask && currentTask instanceof ReindentTask) { // split accumulated reformat range into two if (accumulatedTask.getStartOffset() < currentTask.getStartOffset()) { final RangeMarker endOfRange = document.createRangeMarker( accumulatedTask.getStartOffset(), currentTask.getStartOffset()); // add heading reformat part rangesToProcess.add(new ReformatTask(endOfRange)); // and manage heading whitespace because formatter does not edit it in previous action iterator = rangesToProcess.iterator(); //noinspection StatementWithEmptyBody while (iterator.next().getRange() != currentTask.getRange()) ; } final RangeMarker rangeToProcess = document.createRangeMarker(currentTask.getEndOffset(), accumulatedTask.getEndOffset()); freeFormatingActions.add(new ReformatWithHeadingWhitespaceTask(rangeToProcess)); accumulatedTask = currentTask; iterator.remove(); } else { if (!(accumulatedTask instanceof ReindentTask)) { iterator.remove(); boolean withLeadingWhitespace = accumulatedTask instanceof ReformatWithHeadingWhitespaceTask; if (accumulatedTask instanceof ReformatTask && currentTask instanceof ReformatWithHeadingWhitespaceTask && accumulatedTask.getStartOffset() == currentTask.getStartOffset()) { withLeadingWhitespace = true; } else if (accumulatedTask instanceof ReformatWithHeadingWhitespaceTask && currentTask instanceof ReformatTask && accumulatedTask.getStartOffset() < currentTask.getStartOffset()) { withLeadingWhitespace = false; } int newStart = Math.min(accumulatedTask.getStartOffset(), currentTask.getStartOffset()); int newEnd = Math.max(accumulatedTask.getEndOffset(), currentTask.getEndOffset()); RangeMarker rangeMarker; if (accumulatedTask.getStartOffset() == newStart && accumulatedTask.getEndOffset() == newEnd) { rangeMarker = accumulatedTask.getRange(); } else if (currentTask.getStartOffset() == newStart && currentTask.getEndOffset() == newEnd) { rangeMarker = currentTask.getRange(); } else { rangeMarker = document.createRangeMarker(newStart, newEnd); } if (withLeadingWhitespace) { accumulatedTask = new ReformatWithHeadingWhitespaceTask(rangeMarker); } else { accumulatedTask = new ReformatTask(rangeMarker); } } else if (currentTask instanceof ReindentTask) { iterator.remove(); } // TODO[ik]: need to be fixed to correctly process indent inside indent } } if (accumulatedTask != null) { if (accumulatedTask instanceof ReindentTask) { indentActions.add((ReindentTask) accumulatedTask); } else { freeFormatingActions.add(accumulatedTask); } } final List<PostponedAction> result = new ArrayList<PostponedAction>(); Collections.reverse(freeFormatingActions); Collections.reverse(indentActions); if (!freeFormatingActions.isEmpty()) { FormatTextRanges ranges = new FormatTextRanges(); for (PostprocessFormattingTask action : freeFormatingActions) { TextRange range = TextRange.create(action); ranges.add(range, action instanceof ReformatWithHeadingWhitespaceTask); } result.add(new ReformatRangesAction(ranges)); } if (!indentActions.isEmpty()) { ReindentRangesAction reindentRangesAction = new ReindentRangesAction(); for (ReindentTask action : indentActions) { reindentRangesAction.add(action.getRange(), action.getOldIndent()); } result.add(reindentRangesAction); } return result; }
private String setup( String text, Function<String, String> escapeFunction, int highlightStartOffset, int highlightEndOffset, boolean isDisabled, boolean strikeout, boolean isDisabledBeforeHighlight, Color background) { StringBuilder buf = new StringBuilder(); removeAll(); String[] lines = UIUtil.splitText(text, getFontMetrics(BOLD_FONT), myWidthLimit, ','); myOneLineComponents = new OneLineComponent[lines.length]; int lineOffset = 0; boolean hasHighlighting = highlightStartOffset >= 0 && highlightEndOffset > highlightStartOffset; TextRange highlightingRange = hasHighlighting ? new TextRange(highlightStartOffset, highlightEndOffset) : null; for (int i = 0; i < lines.length; i++) { String line = lines[i]; myOneLineComponents[i] = new OneLineComponent(); TextRange lRange = new TextRange(lineOffset, lineOffset + line.length()); TextRange hr = highlightingRange == null ? null : lRange.intersection(highlightingRange); hr = hr == null ? null : hr.shiftRight(-lineOffset); String before = escapeString( hr == null ? line : line.substring(0, hr.getStartOffset()), escapeFunction); String in = hr == null ? "" : escapeString(hr.substring(line), escapeFunction); String after = hr == null ? "" : escapeString(line.substring(hr.getEndOffset(), line.length()), escapeFunction); TextRange escapedHighlightingRange = in.isEmpty() ? null : TextRange.create(before.length(), before.length() + in.length()); buf.append( myOneLineComponents[i].setup( before + in + after, isDisabled, strikeout, background, escapedHighlightingRange)); if (isDisabledBeforeHighlight) { if (highlightStartOffset < 0 || highlightEndOffset > lineOffset) { myOneLineComponents[i].setDisabledBeforeHighlight(); } } add( myOneLineComponents[i], new GridBagConstraints( 0, i, 1, 1, 1, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); lineOffset += line.length(); } return buf.toString(); }