diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/LSPCodeLensEditorFactoryListener.java b/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/LSPCodeLensEditorFactoryListener.java index 603b65706..fdd921b8c 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/LSPCodeLensEditorFactoryListener.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/LSPCodeLensEditorFactoryListener.java @@ -76,6 +76,10 @@ public static LSPCodeLensSupport getCodeLensSupport(@NotNull Editor editor) { } private static void updateViewportLinesAndRefreshCodeVision(@NotNull CodeLensDataResult result, LSPCodeLensSupport codeLensSupport, UnresolvedCodeLensViewportContext context) { + if (!context.isViewportInitialized()) { + // Viewport not initialized yet, cannot determine what to resolve + return; + } if (!result.hasToResolve(context.getFirstViewportLine(), context.getLastViewportLine())) { // No codelens to resolve to the current viewport return; @@ -124,9 +128,23 @@ private static boolean updateViewportLinesAndRefreshCodeVision(@NotNull CodeLens private void attachScrollListener(@NotNull Editor editor) { // Initialize context final var context = getCodeLensResolveContext(editor); + // Adding a listener for visible area changes editor.getScrollingModel().addVisibleAreaListener((e) -> { Rectangle newRect = e.getNewRectangle(); + + // Initialize viewport on first event (when editor is fully rendered) + if (!context.isViewportInitialized() && newRect.width > 0 && newRect.height > 0) { + // First time - initialize viewport even if it hasn't "changed" + // We're on EDT here, and we have a valid rectangle + if (ApplicationManager.getApplication().isReadAccessAllowed()) { + context.updateViewportLines(newRect); + } else { + ReadAction.run(() -> context.updateViewportLines(newRect)); + } + // Don't return - continue to process the event normally + } + if (newRect.equals(e.getOldRectangle())) { // View port range has not changed return; diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/LSPCodeLensProvider.java b/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/LSPCodeLensProvider.java index ed36706c4..0ce03aa93 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/LSPCodeLensProvider.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/LSPCodeLensProvider.java @@ -134,12 +134,21 @@ public CodeVisionState computeCodeVision(@NotNull Editor editor, Void uiData) { // There is some codelens to resolve applicableCodeLens = new ArrayList<>(); var resolveContext = LSPCodeLensEditorFactoryListener.getCodeLensResolveContext(editor); + // Get viewport lines - if not initialized yet (viewport is updated by scroll listener on EDT), + // use a default range to resolve code lenses in the first visible area + int firstLine = resolveContext.getFirstViewportLine(); + int lastLine = resolveContext.getLastViewportLine(); + if (firstLine == -1) { + // Viewport not yet initialized, use a reasonable default (first ~100 lines) + firstLine = 0; + lastLine = 100; + } // Get the codelens to resolve which are inside the view port range (visible lines) @Nullable CompletableFuture visibleCodeLensToResolve = collectApplicableCodeLens(codelensData, applicableCodeLens, - resolveContext.getFirstViewportLine(), - resolveContext.getLastViewportLine()); + firstLine, + lastLine); if (visibleCodeLensToResolve != null) { // Resolve all visible code lens try { diff --git a/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/UnresolvedCodeLensViewportContext.java b/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/UnresolvedCodeLensViewportContext.java index 39f5ecd93..3852330ed 100644 --- a/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/UnresolvedCodeLensViewportContext.java +++ b/src/main/java/com/redhat/devtools/lsp4ij/features/codeLens/UnresolvedCodeLensViewportContext.java @@ -32,8 +32,8 @@ public class UnresolvedCodeLensViewportContext implements Disposable { private static final long VIEWPORT_CHANGE_DELAY_MS = 500L; // Debounce delay before processing viewport changes private final @NotNull Editor editor; - private int firstViewportLine; - private int lastViewportLine; + private int firstViewportLine = -1; + private int lastViewportLine = -1; private long modificationStamp; private volatile Alarm scrollStopAlarm = null; @@ -61,7 +61,7 @@ public void updateViewportLines(@NotNull Rectangle visibleArea) { /** * Gets the first visible line in the editor's viewport. * - * @return The first visible line number. + * @return The first visible line number, or -1 if not yet initialized. */ public int getFirstViewportLine() { return firstViewportLine; @@ -70,12 +70,21 @@ public int getFirstViewportLine() { /** * Gets the last visible line in the editor's viewport. * - * @return The last visible line number. + * @return The last visible line number, or -1 if not yet initialized. */ public int getLastViewportLine() { return lastViewportLine; } + /** + * Checks if the viewport has been initialized. + * + * @return true if viewport lines have been set, false otherwise. + */ + public boolean isViewportInitialized() { + return firstViewportLine != -1; + } + /** * Resolves unresolved code lens elements in the current viewport and refreshes the editor accordingly. * If a previous refresh task is pending, it will be cancelled before scheduling a new one. @@ -136,8 +145,14 @@ public void dispose() { * @return true if the file content has changed and false otherwise. */ public boolean hasFileChanged(@NotNull PsiFile file) { - if (modificationStamp != file.getModificationStamp()) { - modificationStamp = file.getModificationStamp(); + long currentStamp = file.getModificationStamp(); + if (modificationStamp == 0) { + // First time initialization - don't consider this as a change + modificationStamp = currentStamp; + return false; + } + if (modificationStamp != currentStamp) { + modificationStamp = currentStamp; return true; } return false;