Inactive region highlight#1482
Conversation
| @@ -1115,8 +3759,8 @@ | |||
| "darwin" | |||
| ], | |||
| "binaries": [ | |||
| "./bin/Microsoft.VSCode.CPP.Extension.darwin", | |||
| "./bin/Microsoft.VSCode.CPP.IntelliSense.Msvc.darwin" | |||
| "/home/griffin/vs/vscode-cpptools/Extension/bin/Microsoft.VSCode.CPP.Extension.darwin", | |||
There was a problem hiding this comment.
This change to package.json needs to be reverted. Before making any changes to package.json, you need to make sure to undo the changes that occur when re-write the package.json with the runtime version of the file. The make your changes and stage the changes before running the extension again.
There was a problem hiding this comment.
Thanks for catching that! Is there any way we can automate this process for the future? I would like to investigate the possibility if it's worthwhile.
There was a problem hiding this comment.
I'm going to add a new option to our CMakeLists.txt for the language server that will point to your local clone of this instance and copy it into a disposable location so you don't have to run the extension on top of the local repository. (this has been bugging me as well) :)
There was a problem hiding this comment.
Excellent! I will revert the changes as per Sean's comment and keep my eyes peeled for that change in the future.
sean-mcmanus
left a comment
There was a problem hiding this comment.
Not sure why GitHub has me doing 2 reviews.
| }; | ||
| let textEditorDecoration = vscode.window.createTextEditorDecorationType(renderOptions); | ||
|
|
||
| let editor = vscode.window.visibleTextEditors.find(e => e.document.uri.toString() == params.uri); // TODO change to document.uri == params.uri |
There was a problem hiding this comment.
What does this TODO mean?
There was a problem hiding this comment.
This is a TODO that I should have investigated earlier. Most operations within client.ts operate via vscode.Uri, whereas this method only compares the absolute file path via string. @bobbrow opinion on the matter?
There was a problem hiding this comment.
You should probably send the uri in the JSON message instead of the filename.
|
|
||
| private updateInactiveRegions(params: InactiveRegionParams): void { | ||
| let renderOptions: vscode.DecorationRenderOptions = { | ||
| color: "rgba(255,0,255,0.5)" |
There was a problem hiding this comment.
rgba(255,0,255,0.5) [](start = 20, length = 19)
it looks like we still have the test color in here. We need to remember to make a light-themed and dark-themed gray color here,
There was a problem hiding this comment.
Most definitely. I will add different coloration based on light/dark, and I will keep note of it as a discussion point when we talk as a group, and when we find out more about the possibility of opacity.
| let renderOptions: vscode.DecorationRenderOptions = { | ||
| color: "rgba(255,0,255,0.5)" | ||
| }; | ||
| let textEditorDecoration = vscode.window.createTextEditorDecorationType(renderOptions); |
There was a problem hiding this comment.
let textEditorDecoration = vscode.window.createTextEditorDecorationType(renderOptions); [](start = 8, length = 87)
We probably only need to create this object once when the class is first initialized.
| let textEditorDecoration = vscode.window.createTextEditorDecorationType(renderOptions); | ||
|
|
||
| let editor = vscode.window.visibleTextEditors.find(e => e.document.uri.toString() == params.uri); // TODO change to document.uri == params.uri | ||
| editor.setDecorations(textEditorDecoration, params.ranges); |
There was a problem hiding this comment.
editor.setDecorations [](start = 8, length = 21)
with each notification, I think we'll need to save the ranges that come in. This way we can clear out the old decorations before setting the new ones.
There was a problem hiding this comment.
It looks like you might also be able to call dispose on the TextEditorDecorationType to remove all decorations associated with that object. If that's the case, then my previous comment about creating the TextEditorDecorationType only once would be invalid. You might be able to just keep a reference to the previous TextEditorDecorationType and dispose it before creating a new one and assigning it to the new ranges.
In reply to: 163304083 [](ancestors = 163304083)
There was a problem hiding this comment.
That sounds like a fairly tidy way to manage the decoration types. I will make sure to investigate that possibility first!
| @@ -0,0 +1,170 @@ | |||
|
|
|||
There was a problem hiding this comment.
This is only needed for OSX. Please do not include this in the check-in.
I think it would be ok to add this to the .gitignore. @pieandcakes?
There was a problem hiding this comment.
@grdowns Was this added on purpose because you have a requirement for Mono now?
There was a problem hiding this comment.
No, I'm pretty sure we don't have a requirement for Mono with this change.
There was a problem hiding this comment.
This license was auto-generated. I believe Sean is correct and it will be removed.
| @@ -1,3 +1,3 @@ | |||
| { | |||
| "intelliSenseEngine_default_percentage": 100 | |||
| { | |||
There was a problem hiding this comment.
git diff says this is a whitespace difference, specifically a carriage return (^M). Undo.
There was a problem hiding this comment.
I will make sure to undo this change. Do we have any tools for Git to automatically ignore carriage return changes? I feel that checking for carriage returns manually with each commit is wasteful.
There was a problem hiding this comment.
You could try git diff -w | git apply --cached --ignore-whitespace. However, I would do a quick glance atgit diff before creating the PR.
The common things to look out for with this repo is any changes that you did not make or files that you did not add should not be included with your changes.
There was a problem hiding this comment.
Thanks! I appreciate the advice + tip. You are totally right about the automatically generated changes and I will make sure to be diligent in scrutinizing these diffs pre-PR.
| "--pack_alignment", | ||
| "8", | ||
| "--framework_include_directory=/System/Library/Frameworks" | ||
| "8" |
There was a problem hiding this comment.
This should go in at some point though it's not required to be part of this change. This repo is out of sync with the language server.
| @@ -0,0 +1,170 @@ | |||
|
|
|||
There was a problem hiding this comment.
@grdowns Was this added on purpose because you have a requirement for Mono now?
| @@ -38,7 +38,25 @@ | |||
| "Linters" | |||
| ], | |||
There was a problem hiding this comment.
I think you need to undo this file change. I dont' think we should be changing our activation from *.
| this.model.tagParserStatus.Value = notificationBody.status; | ||
| } | ||
|
|
||
| private decoration : vscode.TextEditorDecorationType; |
There was a problem hiding this comment.
Please move this up to the top of the class definition with the other member variables. You might also want to rename it something more specific so we don't lose track of it. e.g. inactiveRegionsDecoration.
|
|
||
| // Recycle the active text decorations when we receive a new set of inactive regions | ||
| if (this.inactiveRegionsDecoration !== undefined) { | ||
| this.inactiveRegionsDecoration.dispose(); |
There was a problem hiding this comment.
Thinking about this a bit more... Since the inactiveRegionsDecorarion is linked to the Client, this will end up accidentally deleting highlights from files when you have more than one file open in the editor. You're going to want to have one of these for each uri that you encounter.
And then you will want to add disposal code to DefaultClient.dispose
| "stopOnEntry": false, | ||
| "sourceMaps": true, | ||
| "outDir": "${workspaceRoot}/out/src", | ||
| "outFiles": ["${workspaceRoot}/out/src"], |
There was a problem hiding this comment.
Reading the helptext on outFiles, looks like its a glob pattern to specify js files. do we want to set this to "${workspaceRoot}/out/src/**/*.js" ?
| private crashTimes: number[] = []; | ||
| private failureMessageShown = new PersistentState<boolean>("DefaultClient.failureMessageShown", false); | ||
| private isSupported: boolean = true; | ||
| private inactiveRegionsDecorations = new Map<string, [vscode.TextEditorDecorationType, vscode.Range[]]>(); |
There was a problem hiding this comment.
nit: Can you make this an interface?
valuePair[0].dispose(); is not as readable as valuePair.decoration.dispose();
and valuePair[1] = params.ranges; vs valuePair.ranges = params.ranges;
There was a problem hiding this comment.
Absolutely! I considered doing so, but decided against it as it didn't seem worth polluting the file + namespace. I think that someone else requesting an interface is enough to rationalize doing it, however. I'll put it through!
| //Apply text decorations to inactive regions | ||
| for (let e of editors) { | ||
| let valuePair: [vscode.TextEditorDecorationType, vscode.Range[]] = this.inactiveRegionsDecorations.get(e.document.uri.toString()); | ||
| e.setDecorations(valuePair[0], valuePair[1]); // VSCode clears the decorations when the text editor becomes invisible |
There was a problem hiding this comment.
need to guard against valuePair being undefined here.
There was a problem hiding this comment.
Guard has been brought back in + using if (valuePair) instead of if (valuePair !== undefined)
|
|
||
| private updateInactiveRegions(params: InactiveRegionParams): void { | ||
| let renderOptions: vscode.DecorationRenderOptions = { | ||
| light: { color: "rgba(125,125,125,1.0)" }, |
There was a problem hiding this comment.
nit: personal preference (being a Light user 😄): I built this change and am playing with it. This is a bit too dark to easily distinguish the inactive regions for me. Can you bump it up a bit? 175,175,175 looks a bit better to me.
There was a problem hiding this comment.
Definitely! I don't expect these numbers to survive until the feature is complete
…rd against undefined return value
| return new NullClient(); | ||
| } | ||
|
|
||
| interface decorationRangesPair { |
There was a problem hiding this comment.
nit: Please move it closer to the other group of interfaces.
| return new NullClient(); | ||
| } | ||
|
|
||
| interface decorationRangesPair { |
| //Apply text decorations to inactive regions | ||
| for (let e of editors) { | ||
| let valuePair: decorationRangesPair = this.inactiveRegionsDecorations.get(e.document.uri.toString()); | ||
| //if (valuePair !== undefined) { |
There was a problem hiding this comment.
@bobbrow is correct. Apologies while I get used to the code review cycle. All tips and advice and nitpicks are welcome. 😄
| valuePair.decoration.dispose(); | ||
| valuePair.decoration = decoration; | ||
|
|
||
| valuePair.ranges = params.ranges; // As vscode.TextEditor.setDecorations only applies to visible editors, we must cache the range for when another editor becomes visible |
|
|
||
| // Recycle the active text decorations when we receive a new set of inactive regions | ||
| let valuePair: decorationRangesPair = this.inactiveRegionsDecorations.get(params.uri); | ||
| if (valuePair !== undefined) { |
There was a problem hiding this comment.
Either do !valuePair or this.inactiveRegionsDecorations.has(params.uri)
There was a problem hiding this comment.
!valuePair changes the meaning of the statement, and this.inactiveRegionsDecorations.has(params.uri) is (assumedly) as expensive as calling this.inactiveRegionsDecorations.get(params.uri) which while minor it would be best to avoid it. Is that the case?
There was a problem hiding this comment.
no need to call .has. You can change it to if (valuePair) or just leave it as if (valuePair !== undefined). I think the 'truthy' compare argument for this case has been bolstered a bit by the recent regression, but I believe the API contract here is relatively well defined.
interface Map<K, V> {
clear(): void;
delete(key: K): boolean;
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
get(key: K): V | undefined;
has(key: K): boolean;
set(key: K, value: V): this;
readonly size: number;
}
There was a problem hiding this comment.
Whoops, should have looked at the return values of get(). 🙈
-resolved-
There was a problem hiding this comment.
I believe if (valuePair) is more idiomatic and as it does not change the meaning of the statement, I will substitute it in. Thanks
| import { DataBinding } from './dataBinding'; | ||
| import minimatch = require("minimatch"); | ||
| import * as logger from '../logger'; | ||
| import { deactivate } from './extension'; |
There was a problem hiding this comment.
This should not be imported here. Only vscode should ever call this method.
There was a problem hiding this comment.
That snuck in via autocomplete. Removed + noted for the future
…into inactive-region-highlight
…oft/vscode-cpptools into inactive-region-highlight
| return false; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Did you also want a reference compare or actual equality?
https://github.com/Microsoft/vscode/blob/69f9a3b8080f5e90a47743dda1a6dc3f55972be4/src/vs/vscode.d.ts#L422
There was a problem hiding this comment.
Good catch! I was ignorant of the reference vs primitive comparison difference in this case. if (!e1 == e2) should be if (!e1.isEqual(e2)) as it will compare the ints inside each range's positions.
| } | ||
|
|
||
| // Helper method to compare two ranges for equality | ||
| private isRangesEqual(r1: vscode.Range[], r2: vscode.Range[]): boolean { |
There was a problem hiding this comment.
nit: comparing two things. Use "are" instead of "is" for the naming. :)
There was a problem hiding this comment.
It's a stylistic choice for a method returning a boolean. But I see your point and I'll concede. 😆
|
|
||
| for (let e1 of r1) { | ||
| for (let e2 of r2) { | ||
| if (!e1.isEqual(e2)) { |
There was a problem hiding this comment.
This seems wrong. It will compare r1[0] against r2[1] and fail. If we are expecting the arrays to have the same ranges in the same order, this should be a single for-loop iterating from 0 to r1.length-1 (or r2.length-1 since they are equal at this point). Then it checks if r1[n] is equal to r2[n].
There was a problem hiding this comment.
Are the arrays always going to have the Range in the same order?
If we are not guaranteedsame order, I think it should be e1 exists in e2, if it does not return false.
There was a problem hiding this comment.
D'oh. This is n squared as well as ineffective. Thanks
| // Recycle the active text decorations when we receive a new set of inactive regions | ||
| let valuePair: DecorationRangesPair = this.inactiveRegionsDecorations.get(params.uri); | ||
| if (valuePair) { | ||
| // The language server will send notifications regardless of whether the ranges have changed. Unfortunately we must check for changes ourselves |
There was a problem hiding this comment.
The "unfortunately" part of this comment is implying that there is a problem with the language server we are working around. As we discussed earlier, we are making a conscious choice to do it this way and avoid a second copy of the cached results in the language server. Perhaps this is unfortunate, but it is deliberate, and I don't think this comment helps us understand the code better or feel better about that decision, so my vote is to remove it. 😉
There was a problem hiding this comment.
Good point! I totally agree with that and it will be removed. 😄
|
https://github.com/Microsoft/vscode-cpptools/blob/master/Extension/test/unitTests/extension.test.ts is pretty empty. Never hurts to have more tests. |
Prepare for inactive region highlighting feature by adding a notification to client.ts for text decoration. Also fix the deprecated changes in launch.json + add some auto-generated changes which are seemingly necessary.