public Map<TemplateImpl, String> findMatchingTemplates( final PsiFile file, Editor editor, @Nullable Character shortcutChar, TemplateSettings templateSettings) { final Document document = editor.getDocument(); CharSequence text = document.getCharsSequence(); final int caretOffset = editor.getCaretModel().getOffset(); List<TemplateImpl> candidatesWithoutArgument = findMatchingTemplates(text, caretOffset, shortcutChar, templateSettings, false); int argumentOffset = passArgumentBack(text, caretOffset); String argument = null; if (argumentOffset >= 0) { argument = text.subSequence(argumentOffset, caretOffset).toString(); if (argumentOffset > 0 && text.charAt(argumentOffset - 1) == ' ') { if (argumentOffset - 2 >= 0 && Character.isJavaIdentifierPart(text.charAt(argumentOffset - 2))) { argumentOffset--; } } } List<TemplateImpl> candidatesWithArgument = findMatchingTemplates(text, argumentOffset, shortcutChar, templateSettings, true); if (candidatesWithArgument.isEmpty() && candidatesWithoutArgument.isEmpty()) { return null; } candidatesWithoutArgument = filterApplicableCandidates(file, caretOffset, candidatesWithoutArgument); candidatesWithArgument = filterApplicableCandidates(file, argumentOffset, candidatesWithArgument); Map<TemplateImpl, String> candidate2Argument = new HashMap<TemplateImpl, String>(); addToMap(candidate2Argument, candidatesWithoutArgument, null); addToMap(candidate2Argument, candidatesWithArgument, argument); return candidate2Argument; }
@Nullable public Runnable prepareTemplate( final Editor editor, char shortcutChar, @Nullable final PairProcessor<String, String> processor) { if (editor.getSelectionModel().hasSelection()) { return null; } PsiFile file = PsiUtilBase.getPsiFileInEditor(editor, myProject); if (file == null) return null; Map<TemplateImpl, String> template2argument = findMatchingTemplates(file, editor, shortcutChar, TemplateSettings.getInstance()); List<CustomLiveTemplate> customCandidates = ContainerUtil.findAll( CustomLiveTemplate.EP_NAME.getExtensions(), customLiveTemplate -> shortcutChar == customLiveTemplate.getShortcut() && (editor.getCaretModel().getCaretCount() <= 1 || supportsMultiCaretMode(customLiveTemplate))); if (!customCandidates.isEmpty()) { int caretOffset = editor.getCaretModel().getOffset(); PsiFile fileCopy = insertDummyIdentifierIfNeeded(file, caretOffset, caretOffset, ""); Document document = editor.getDocument(); for (final CustomLiveTemplate customLiveTemplate : customCandidates) { if (isApplicable(customLiveTemplate, editor, fileCopy)) { final String key = customLiveTemplate.computeTemplateKey(new CustomTemplateCallback(editor, fileCopy)); if (key != null) { int offsetBeforeKey = caretOffset - key.length(); CharSequence text = document.getImmutableCharSequence(); if (template2argument == null || !containsTemplateStartingBefore( template2argument, offsetBeforeKey, caretOffset, text)) { return () -> customLiveTemplate.expand(key, new CustomTemplateCallback(editor, file)); } } } } } return startNonCustomTemplates(template2argument, editor, processor); }
private static List<TemplateImpl> filterApplicableCandidates( PsiFile file, int caretOffset, List<TemplateImpl> candidates) { if (candidates.isEmpty()) { return candidates; } PsiFile copy = insertDummyIdentifierIfNeeded( file, caretOffset, caretOffset, CompletionUtil.DUMMY_IDENTIFIER_TRIMMED); List<TemplateImpl> result = new ArrayList<TemplateImpl>(); for (TemplateImpl candidate : candidates) { if (isApplicable(copy, caretOffset - candidate.getKey().length(), candidate)) { result.add(candidate); } } return result; }
public static List<TemplateImpl> findMatchingTemplates( CharSequence text, int caretOffset, @Nullable Character shortcutChar, TemplateSettings settings, boolean hasArgument) { List<TemplateImpl> candidates = Collections.emptyList(); for (int i = settings.getMaxKeyLength(); i >= 1; i--) { int wordStart = caretOffset - i; if (wordStart < 0) { continue; } String key = text.subSequence(wordStart, caretOffset).toString(); if (Character.isJavaIdentifierStart(key.charAt(0))) { if (wordStart > 0 && Character.isJavaIdentifierPart(text.charAt(wordStart - 1))) { continue; } } candidates = settings.collectMatchingCandidates(key, shortcutChar, hasArgument); if (!candidates.isEmpty()) break; } return candidates; }