Skip to content

Commit

Permalink
fix: HTML completion / autoclose is broken when offset is inside a Qute
Browse files Browse the repository at this point in the history
section (#787)

Fixes #787

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Jul 10, 2023
1 parent 0f081b9 commit 3622262
Show file tree
Hide file tree
Showing 46 changed files with 2,369 additions and 269 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ public class SupportedFeatures {
textDocumentClientCapabilities.setInlayHint(new InlayHintCapabilities());
// TODO : support textDocument/colorPresentation
// textDocumentClientCapabilities.setColorProvider(new ColorProviderCapabilities());
final var completionItemCapabilities = new CompletionItemCapabilities(Boolean.TRUE);
final var completionItemCapabilities = new CompletionItemCapabilities(Boolean.FALSE);
completionItemCapabilities
.setDocumentationFormat(Arrays.asList(MarkupKind.MARKDOWN, MarkupKind.PLAINTEXT));
completionItemCapabilities.setInsertTextModeSupport(new CompletionItemInsertTextModeSupportCapabilities(List.of(InsertTextMode.AsIs, InsertTextMode.AdjustIndentation)));
completionItemCapabilities.setResolveSupport(new CompletionItemResolveSupportCapabilities(List.of("documentation", "detail", "additionalTextEdits"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
// completionItemCapabilities.setInsertTextModeSupport(new CompletionItemInsertTextModeSupportCapabilities(List.of(InsertTextMode.AsIs, InsertTextMode.AdjustIndentation)));
// completionItemCapabilities.setResolveSupport(new CompletionItemResolveSupportCapabilities(List.of("documentation", "detail", "additionalTextEdits"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
textDocumentClientCapabilities.setCompletion(new CompletionCapabilities(completionItemCapabilities));
final var definitionCapabilities = new DefinitionCapabilities();
definitionCapabilities.setLinkSupport(Boolean.TRUE);
Expand Down Expand Up @@ -115,11 +115,13 @@ public class SupportedFeatures {
textDocumentClientCapabilities.setOnTypeFormatting(null); // TODO
// TODO : support textDocument/rangeFormatting
// textDocumentClientCapabilities.setRangeFormatting(new RangeFormattingCapabilities());
textDocumentClientCapabilities.setReferences(new ReferencesCapabilities());
final var renameCapabilities = new RenameCapabilities();
renameCapabilities.setPrepareSupport(true);
textDocumentClientCapabilities.setRename(renameCapabilities);
// TODO
// TODO : support textDocument/references
// textDocumentClientCapabilities.setReferences(new ReferencesCapabilities());
// TODO : support textDocument/rename
//final var renameCapabilities = new RenameCapabilities();
//renameCapabilities.setPrepareSupport(true);
//textDocumentClientCapabilities.setRename(renameCapabilities);
// TODO : support textDocument/signatureHelp
// textDocumentClientCapabilities.setSignatureHelp(new SignatureHelpCapabilities());
textDocumentClientCapabilities
.setSynchronization(new SynchronizationCapabilities(Boolean.TRUE, Boolean.TRUE, Boolean.TRUE));
Expand Down Expand Up @@ -151,9 +153,9 @@ public class SupportedFeatures {

public static WindowClientCapabilities getWindowClientCapabilities() {
final var windowClientCapabilities = new WindowClientCapabilities();
windowClientCapabilities.setShowDocument(new ShowDocumentCapabilities(true));
windowClientCapabilities.setWorkDoneProgress(true);
windowClientCapabilities.setShowMessage(new WindowShowMessageRequestCapabilities());
//windowClientCapabilities.setShowDocument(new ShowDocumentCapabilities(true));
//windowClientCapabilities.setWorkDoneProgress(true);
//windowClientCapabilities.setShowMessage(new WindowShowMessageRequestCapabilities());
return windowClientCapabilities;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public int getPrefixCompletionStart(Document document, int completionOffset) {
@NotNull
@Override
public String getLookupString() {
String lookup = StringUtils.isNotBlank(item.getSortText())?item.getSortText():item.getLabel();
String lookup = StringUtils.isNotBlank(item.getFilterText())?item.getFilterText():item.getLabel();
if (lookup.charAt(0) == '@') {
return lookup.substring(1);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.lsp4ij.operations.completion;

import com.intellij.codeInsight.completion.CompletionConfidence;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;

/**
* Provides the capability to open completion anywhere.
*/
public class LSPCompletionConfidence extends CompletionConfidence {

@Override
public @NotNull ThreeState shouldSkipAutopopup(@NotNull PsiElement contextElement, @NotNull PsiFile psiFile, int offset) {
return ThreeState.NO;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.lsp4ij.operations.highlight;

import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.PsiElementBase;
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
import org.eclipse.lsp4j.DocumentHighlight;
import org.eclipse.lsp4j.DocumentHighlightKind;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Implement a fake {@link PsiElement} which stores the required text edit (coming from Language server) to highlight.
*
* This class provides the capability to highlight part of code by using Language server TextEdit and not by using the PsiElement.
*/
public class LSPHighlightPsiElement extends PsiElementBase {

private final TextRange textRange;
private final DocumentHighlightKind kind;

public LSPHighlightPsiElement(TextRange textRange, DocumentHighlightKind kind) {
this.textRange = textRange;
this.kind = kind;
}

public DocumentHighlightKind getKind() {
return kind;
}

@Override
public @NotNull Language getLanguage() {
return null;
}

@Override
public PsiElement @NotNull [] getChildren() {
return new PsiElement[0];
}

@Override
public PsiElement getParent() {
return null;
}

@Override
public TextRange getTextRange() {
return textRange;
}

@Override
public int getStartOffsetInParent() {
return 0;
}

@Override
public int getTextLength() {
return 0;
}

@Override
public @Nullable PsiElement findElementAt(int offset) {
return null;
}

@Override
public int getTextOffset() {
return 0;
}

@Override
public @NlsSafe String getText() {
return null;
}

@Override
public char @NotNull [] textToCharArray() {
return new char[0];
}

@Override
public ASTNode getNode() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,41 @@
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.Consumer;
import org.eclipse.lsp4j.DocumentHighlightKind;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.logging.Logger;

public class LSPHighlightUsagesHandler extends HighlightUsagesHandlerBase<PsiElement> {
public class LSPHighlightUsagesHandler extends HighlightUsagesHandlerBase<LSPHighlightPsiElement> {
private static final Logger LOGGER = Logger.getLogger(LSPHighlightUsagesHandler.class.getName());
private final List<PsiElement> targets;
private final List<LSPHighlightPsiElement> targets;

public LSPHighlightUsagesHandler(Editor editor, PsiFile file, List<PsiElement> targets) {
public LSPHighlightUsagesHandler(Editor editor, PsiFile file, List<LSPHighlightPsiElement> targets) {
super(editor, file);
this.targets = targets;
}

@Override
public @NotNull List<PsiElement> getTargets() {
public @NotNull List<LSPHighlightPsiElement> getTargets() {
return targets;
}

@Override
protected void selectTargets(@NotNull List<? extends PsiElement> targets,
@NotNull Consumer<? super List<? extends PsiElement>> selectionConsumer) {
protected void selectTargets(@NotNull List<? extends LSPHighlightPsiElement> targets,
@NotNull Consumer<? super List<? extends LSPHighlightPsiElement>> selectionConsumer) {
selectionConsumer.consume(targets);
}

@Override
public void computeUsages(@NotNull List<? extends PsiElement> targets) {
targets.forEach(target -> myReadUsages.add(target.getTextRange()));
public void computeUsages(@NotNull List<? extends LSPHighlightPsiElement> targets) {
targets.forEach(target ->
{
if (target.getKind() == DocumentHighlightKind.Read) {
myReadUsages.add(target.getTextRange());
} else {
myWriteUsages.add(target.getTextRange());
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import com.intellij.codeInsight.highlighting.HighlightUsagesHandlerFactory;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
Expand Down Expand Up @@ -43,12 +45,12 @@ public class LSPHighlightUsagesHandlerFactory implements HighlightUsagesHandlerF

@Override
public @Nullable HighlightUsagesHandlerBase createHighlightUsagesHandler(@NotNull Editor editor, @NotNull PsiFile file) {
List<PsiElement> targets = getTargets(editor, file);
List<LSPHighlightPsiElement> targets = getTargets(editor, file);
return targets.isEmpty()?null:new LSPHighlightUsagesHandler(editor, file, targets);
}

private List<PsiElement> getTargets(Editor editor, PsiFile file) {
List<PsiElement> elements = new ArrayList<>();
private List<LSPHighlightPsiElement> getTargets(Editor editor, PsiFile file) {
List<LSPHighlightPsiElement> elements = new ArrayList<>();
try {
int offset = TargetElementUtil.adjustOffset(file, editor.getDocument(), editor.getCaretModel().getOffset());
Document document = editor.getDocument();
Expand Down Expand Up @@ -76,13 +78,14 @@ private List<PsiElement> getTargets(Editor editor, PsiFile file) {
ProgressManager.checkCanceled();
DocumentHighlight highlight = highlights.poll(25, TimeUnit.MILLISECONDS);
if (highlight != null) {
int highlightOffset = LSPIJUtils.toOffset(highlight.getRange().getStart(), document);
PsiElement element = file.findElementAt(highlightOffset);
if (element != null) {
elements.add(element);
TextRange textRange = LSPIJUtils.toTextRange(highlight.getRange(), document);
if (textRange != null) {
elements.add(new LSPHighlightPsiElement(textRange, highlight.getKind()));
}
}
}
} catch (ProcessCanceledException cancellation){
throw cancellation;
} catch (InterruptedException e) {
LOGGER.log(Level.WARNING, e, e::getLocalizedMessage);
}
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/com/redhat/devtools/intellij/qute/QuteBundle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.qute;

import com.intellij.DynamicBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.PropertyKey;

import java.util.function.Supplier;

/**
* Qute messages bundle.
*/
public final class QuteBundle extends DynamicBundle {

@NonNls public static final String BUNDLE = "messages.QuteBundle";
private static final QuteBundle INSTANCE = new QuteBundle();

private QuteBundle() {
super(BUNDLE);
}

@NotNull
public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
return INSTANCE.getMessage(key, params);
}

@NotNull
public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
return INSTANCE.getLazyMessage(key, params);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.qute.lang;

import com.intellij.lang.ASTFactory;
import com.intellij.psi.impl.source.tree.LeafElement;
import com.intellij.psi.templateLanguages.OuterLanguageElementImpl;
import com.intellij.psi.tree.IElementType;
import com.redhat.devtools.intellij.qute.lang.psi.QuteToken;
import com.redhat.devtools.intellij.qute.lang.psi.QuteElementTypes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Qute AST factory.
*/
public class QuteASTFactory extends ASTFactory {

@Override
public @Nullable LeafElement createLeaf(@NotNull IElementType type, @NotNull CharSequence text) {
if (type == QuteElementTypes.QUTE_OUTER_ELEMENT_TYPE) {
// HTML, YAML, etc content
return new OuterLanguageElementImpl(type, text);
}
// Qute content
return new QuteToken(type, text);
}
}
Loading

0 comments on commit 3622262

Please sign in to comment.