Skip to content

Feature: don't show error peek overlay when navigating over errors (next/prev error by F8 hotkey) #245092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

n-gist
Copy link
Contributor

@n-gist n-gist commented Mar 31, 2025

Adds ZoneWidget showOverlay (true) option to skip insertion of overlayWidget if set to false

Adds problems.gotoError.showOverlay setting to make use of it when navigating over errors (next/prev error by F8 hotkey)

Fixes #51787
Fixes #63591

@n-gist n-gist changed the title Option zonewidget overlay suppression ZoneWidget overlay suppression option Mar 31, 2025
@n-gist n-gist marked this pull request as draft March 31, 2025 04:33
@n-gist
Copy link
Contributor Author

n-gist commented Mar 31, 2025

Made error overlay still shown on clicking View Problem from hover widget, by adding forceShowOverlay parameter to showAtMarker method

Hid the hotkey hint in brackets on View Problem (Alt + F8) button if setting is set to false

Open question. I tried to retrieve setting inside MarkerController constructor to cache it for further use, but it seems that MarkerController doesn't get recreated on settings edits. So I made a getter which retrieves it every time. I don't feel it right, but I don't know how to do it properly. Maybe it should be boxed into something adaptive to settings updates?

@n-gist n-gist marked this pull request as ready for review March 31, 2025 07:55
@n-gist
Copy link
Contributor Author

n-gist commented Mar 31, 2025

I looked at how it was done in other places and added a disposable callback for settings updates. Now it looks correct to me

@n-gist n-gist changed the title ZoneWidget overlay suppression option Feature: don't show error peek overlay when navigating over errors (next/prev error by F8 hotkey) Apr 2, 2025
@n-gist
Copy link
Contributor Author

n-gist commented Apr 10, 2025

@sandy081 check please, it looks complete to me, but maybe I should change it or do it other way?

Regarding of adding forceShowOverlay to showAtMarker - actually this may be not necessary, since showAtMarker is used only in one place, from hover widget View Problem button click, and thus it can be made to always force to show. I have added it to make it more verbose if it is going to be called from somewhere else in the future. But I'm not sure if it is needed still, since showAtMarker can be read as 'just show it at the specified marker'. So, it can be kept or removed

@n-gist
Copy link
Contributor Author

n-gist commented May 8, 2025

@jrieken sorry, I don't know who to ping for, but probably it is your area? Seems like @sandy081 is busy

@jrieken jrieken assigned jrieken and unassigned sandy081 May 8, 2025
@jrieken
Copy link
Member

jrieken commented May 8, 2025

Thanks for the effort here. Tho, we should discussed first if this contribution will be taken. There are not many upvotes on either feature requests and the gist of the F8 feature is to peek into errors, not to navigate across them.

Taking a PR always comes with the maintenance cost and the feature you are asking for can also be done as extension (vscode.languages.getDiagnostics and a command) or many with some keybinding configuration from the problems view

@n-gist
Copy link
Contributor Author

n-gist commented May 9, 2025

@jrieken I see that my implementation is wrong, it should be done as a different command, instead of as configuration setting. I didn't really think about implementing this as an extension. I guess I can do that. If all the API needed for this is available to extensions, that's a good solution. Thanks

But since we're already here. If I can add my two cents to why this might be wanted to be built into editor

Why not many upvotes

One of the reasons is that command named not accurate, because it is named as Go to, but does Go to and Peek. It's a bit strange to ask about a command that formally already exists, and even more so about cutting its functionality. Maybe if it was named correctly there would be more votes for the raw Go to command. But now, you just look for the setting to disable the widget on jumping, find nothing, give up and live with what is there, just hit Esc every time. For example, it took me a couple of years before I decided to do something about it

Why someone might not want information about a Problem. Cases

a) For overall usage. It would be actually interesting to gather statistics about the percentage ratio of immediately closing peek overlay to keeping it open for more than two seconds. But subjectively the reading frequency will be much lower than 50 percent, since most often the problem is clear because code segment is underlined, or even decorated in an additional way (dimmed, etc.) which gives understanding of the issue faster, than reading error description. But everyone can check himself - how often you hit Esc immediately? It's just not noticeable until you pay attention to this fact
b) An extension can be used that prints error messages inlined, such as Error Lens
c) You don't intend to fix the problems right now, you just want to check the areas affected by the problems-producing change and jump back to it
d) You know the problems in advance, because you just did a change that produced them. Actually this is the main case in this list, especially when you do refactoring in a stable, free of errors project

Why it is essential, from UX view

Even if peek is useful in less than 50% of cases, it is still good to have it by default, this makes it user-friendly, I understand that. Not a big deal to just close it. But the option to opt out of it is really missing. Since this is not information somewhere on the side that can be ignored. It is a feature that requires action to be taken to reject it. Physical movements to hit Esc and back to initial position of a hand, this takes time. Peek overlay breaks the code where it is inserted and collapses it back when closed. Jumping code is a strain on the eyes and attention. It delays the moment when the code begins to be perceived clearly. This is a cognitive interruption. The ability to skip the peek is a workflow optimization, which is one of the main goals of an editor as I see it. Reducing cognitive noise to maintain attention hygiene. Code, as a first-class editor, imo should provide such options out of the box

If this is reasonable enough, I can try to work on it. My proposal is:

  1. Rename Go to Problem to Peek Problem/Peek to Problem/Go to and Peek Problem. Keep default F8 hotkeys to it
  2. Add Go to Problem commands without assigning default hotkeys

If not, I'm fine to create an extension

@n-gist
Copy link
Contributor Author

n-gist commented May 21, 2025

@jrieken since decision is taking some time, I have tried to write an extension. Done it, but when I tried to jump to closed file, it failed. Seems like vscode.languages.getDiagnostics provides data only for currently open files. It can't be used to get list of problems from, for example, a tsc watcher used as typechecker service. This is crucial. Built-in commands use MarkerService for this. Is there a way to access it? Or get the list from problems view pane? I have found this your issue, looks like related to this #47292

I have also tried to use original Go to commands and execute closeMarkersNavigation right after. It works, but blinks for a moment

@jrieken
Copy link
Member

jrieken commented May 22, 2025

Seems like vscode.languages.getDiagnostics provides data only for currently open files. It can't be used to get list of problems from, for example, a tsc watcher used as typechecker service. This is crucial. Built-in commands use MarkerService for this.

Both, the marker service and getDiagnostics API, use the same data. This forwards all markers from the service into the API. This includes diagnostics from the API as well as from tasks. Tho, there is no guarantee that diagnostics are computed on a project-level, e.g tsserver doesn't do that by default.

@n-gist
Copy link
Contributor Author

n-gist commented May 22, 2025

@jrieken thanks for the info, but it doesn't helps. Am I doing something wrong?

  1. I open one file which cointains several problems
  2. vscode.languages.getDiagnostics() returns entry for this file with a list of problems, as it should
  3. Go to Next Problem in Files (editor.action.marker.nextInFiles) command loops over problems inside this file, and don't jumps to other files, as it should
  4. I launch tsc watcher task, which adds problems from other files to Problems view pane
  5. vscode.languages.getDiagnostics() returns same, unchanged data, cointaining entry for initially opened file only
  6. But Go to Next Problem in Files (editor.action.marker.nextInFiles) now see new problems and jumps to previously not opened files

Is it working as intended? If yes, how to get full list, the same as Go to Problem commands have access to? I tried to follow the flow of code to find differences from there, but I'm losing the track

@jrieken
Copy link
Member

jrieken commented May 22, 2025

Mystery. The problems pane is also just fed from the marker service, afaik there is no other way to feed problems into the system and from there everything is pushed back into the extension host

@n-gist
Copy link
Contributor Author

n-gist commented May 22, 2025

@jrieken, I just thought that it could be because of monoproject (I'm using tsconfig refs), thought maybe it just discards data coming from 'another' project. But no, it is reproducible in very simple project. Here is repo for testing https://github.com/n-gist/getDiagnostics-test
There is vsix which simply outputs getDiagnostics() result to output channel named 'getDiagnostics() test' (Ctrl+F8), as:

const diagnostics = vscode.languages.getDiagnostics()
for (const d of diagnostics) {
	channel.appendLine(`${d[0].toString()}`)
	channel.appendLine(`${d[1].length} entries`)
}

Reproduce steps:

  1. Open main.ts
  2. Ctrl+F8 outputs entry for main.ts only
  3. Start tsc watch task, it adds another.ts to the problems list
  4. Ctrl+F8 still outputs main.ts only
  5. F8 correctly jumps to another.ts
  6. When both files are open, Ctrl+F8 outputs correctly
  7. If the files are closed after that, it still outputs entries for them, but without Diagnostics entries

You can point me to where I can investigate for a chance of finding the source, but I assume my vs code codebase knowledge is not enough to find a fix acceptably fast. Is it there?

Or will you take a look at it yourself sometime?

@n-gist
Copy link
Contributor Author

n-gist commented May 22, 2025

@jrieken, I just opened the repo I created (in previous comment) through Codespaces extension, installed typescript for watch task, this vsix I made, and it works as intended. Step 4 outputs data for both files. And still outputs as it should after closing files (Step 7).
So, there is some sort of difference in behaviour when I run it locally on my Windows desktop machine

Another difference is that locally there is a tsconfig.json URI entry in getDiagnostics() results, without problems entries (In my other project there is also similar entry for package.json URI)

Step 2 (one file is open)
local/codepaces
Screenshot_1
Screenshot_2

Step 4 (tsc watch is running)
Screenshot_3
Screenshot_4

Step 6 (both files are open)
Screenshot_1
Screenshot_2

Step 7 (files closed)
Screenshot_3
Screenshot_4

I tried disabling all extensions and emptying my settings file. Didn't helped

@n-gist
Copy link
Contributor Author

n-gist commented May 24, 2025

@jrieken, I was trying to find the source of issue, so here is what I found

First, I found that DiagnosticCollection.set is not called when kicking watch task
However, it is called from ExtHostDiagnostics.$acceptMarkersChange without entries (clearing call) when task is terminated, for not opened files URIs

So, I checked what happens in MainThreadDiagnostics._forwardMarkers and it turns out that all markers always get filtered out there (even for opened files) because typescript exists in _activeOwners, so data array doesn't get filled, and this._proxy.$acceptMarkersChange(data); is not called

However, when a file is opened, DiagnosticCollection.set is called from somewhere else (not from ExtHostDiagnostics.$acceptMarkersChange and I didn't found from where), before the MainThreadDiagnostics._forwardMarkers call

So, in conclusion, collection is feeded from somewhere by DiagnosticCollection.set for opened files, and MainThreadDiagnostics._forwardMarkers also called after that, but never transmits markers further

I wanted to check how it behaves through codespaces extension for comparison, but it doesn't connects from OSS build

@n-gist
Copy link
Contributor Author

n-gist commented May 24, 2025

Here is one more test I did - if watch task is kicked before opening any file, _forwardMarkers passes markers normally because there is no 'typescript' in _activeOwners yet

@jrieken
Copy link
Member

jrieken commented May 28, 2025

This is a great find. There is something going on with task- and extension-markers. I need to double check but I believe they can share owners so that extension-markers overwrite task-markers but not the other way around.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Disable peek on F8 (linting) Allow F8: Go to next problem in file not opening the inline view
3 participants