Repository navigation
Refactor so isWrapped isn't public writeable - #5788
PerBothner wants to merge 62 commits into
Conversation
Instead to change isWrapped state use a Buffer.setWrapped method. This allows for potential flexibility in how BufferLine and line-wrapping are implemented.
|
It would be great if someone could merge this. It allows (but does not require) alternative implementation stategies for BufferLine, such as PR #5797. I believe this should be trivially reviewable and hopefully non-controversial. |
Can you expand on why this would be needed? Is this an attempt to hide the row logic behind If we go that route with hiding abstraction behind |
|
The motivation of this PR was to split off part of PR #5797 that can be reviewed separately. Like ad hoc "stacked PRs". For #5797 (and probably other alternative Buffer implementation strategies) changing a line from wrapped to non-wrapped or vice versa isn't a matter of just flipping a bit - there are more extensive changes that need to be done. For PR #5797 you would need to split or merge the related LogicalLine objects. So changing the isWrapped state becomes a more expensive operation. (Though note that setting isWrapped is usually when a new line is scrolled in, when a new BufferLine is created. Clearing isWrapped is usually when a line or buffer is erased, so those operations can be combined.)
Most of the other changes involving LogicalLine are hidden inside BufferLine.js (except for buffer reflow in Buffer.ts, which becomes vastly simpler and more efficient), but changing isWrapped to read-only is the main API change. It would probably be straightforward to make isWrapped is a
PR #5797 makes it trivial to see if the current line wraps to the next one: Just check Perhaps it would be more useful to come back this PR after looking at PR #5797. If you prefer, I can merge this into the latter, making the latter slightly larger, but perhaps better justified. I am also interested in exploring this Marker proposal, which I think will have significant performance and extensibility advantages, but I think PR #5797 needs to be merged first. |
Bumps [axios](https://github.com/axios/axios) from 1.13.2 to 1.15.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](axios/axios@v1.13.2...v1.15.0) --- updated-dependencies: - dependency-name: axios dependency-version: 1.15.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com>
Disable desynchronized 2D canvas mode for image layers so resize paint stays synchronized and avoids blank-frame jitter on some platforms. Signed-off-by: sergiochan <yuheng9211@qq.com>
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.11 to 1.16.0. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](follow-redirects/follow-redirects@v1.15.11...v1.16.0) --- updated-dependencies: - dependency-name: follow-redirects dependency-version: 1.16.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com>
- change interface to IFunctionIdentifier (API change) - extend parser states APC_ENTRY, APC_INTERMEDIATE, APC_PASSTHROUGH - remove APC_STRING - change ApcParser.start to retrieve ident - change actions APC_START and APC_PUT
Broke due to 2 recent conflicting PRs
This allows O(1) clearing of the cache, a single TTL timer and we can avoid making BufferLine's Disposable
Bit hacky, but this is due to the way we're serializing the line in the test
|
This is part of the large PR #6160. |
jerch
left a comment
There was a problem hiding this comment.
LGTM 👍
I have a few remarks below, but nothing blocking. Plz let me know, if you want to address some of them, otherwise this looks ready to merge.
|
|
||
| public setWrapped(absrow: number, value: boolean): void { | ||
| const line = this.lines.get(absrow); | ||
| line instanceof BufferLine && line.setWrapped(value); |
There was a problem hiding this comment.
The && invocation is an interesting pattern here, I guess you did it for speed reasons. I also found && to be much faster on v8 compared to ordinary branching.
Minor perf suggestion - if the instanceof check is not needed (because .get() will always return either something nullish or a bufferline), then we should prolly just test for truthiness.
There was a problem hiding this comment.
IIRC I used the X && Y pattern because lint would complain about if (X) Y, though it did allow if (X) {Y}, which I though a bit inelegant. I actually think if (X) Y is slightly for readable - but if X && Y is faster we might as well keep it.
The instanceof check is because IBufferLine specifically does not provide setWrapped, which is supposed to used only to implement Buffer.setWrapped. I made a change to get rid of BufferLine.setWrapped completely - instead you have to do (line as any)._isWrapped. That should make it clear(er) you're mucking about with internals.
| this._cachedBlankLine = newLine; | ||
| } | ||
| newLine.isWrapped = isWrapped; | ||
| (newLine as BufferLine).setWrapped(isWrapped); |
There was a problem hiding this comment.
Do we have an interface issue here? Isn't buffer.getBlankLine meant to always return a bufferline?
There was a problem hiding this comment.
As above. Replaced by (newLine as any)._isWrapped = isWrapped.
Note the assignment is only needed for the case we don't call getBlankLine, so I put it in an else branch..
| ); | ||
| if (clearWrap) { | ||
| line.isWrapped = false; | ||
| this._activeBuffer.setWrapped(this._activeBuffer.ybase + y, false); |
There was a problem hiding this comment.
Is there a reason for using absolute addressing here now, why not on the line?
There was a problem hiding this comment.
Not sure I understand the question. Buffer.setWrapped takes an absolute line number. We don't want to use BufferLine.setWrapped (now removed) because it is internal.
Note one reason for removing BufferLine.setWrapped (which is the same reason for making BufferLine.isWrapped read-only) is because some implementations (including the proposed LogicalLine implementation) need more state, and modifying isWrapped can't be done without access to at least the previous line.
| line.fill(this._activeBuffer.getNullCell(this._eraseAttrData()), respectProtect); | ||
| this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase + y); | ||
| line.isWrapped = false; | ||
| this._activeBuffer.setWrapped(this._activeBuffer.ybase + y, false); |
There was a problem hiding this comment.
Same question as above - why the absolute addressing now?
| if (nextLine) { | ||
| nextLine.isWrapped = false; | ||
| } | ||
| this._activeBuffer.setWrapped(j + 1, false); |
There was a problem hiding this comment.
These n+1 lookups for wrapped state are really annoying. I think I already addressed it in some comment elsewhere - we basically have a slightly off handling of wrapped state:
We set the flag on the next line to indicate, that it continues from the previous one. This introduces a lot of nasty edge cases, where we have to fix wrapped on n+1.
A more logical place would be to store it on the n-th line to indicate, that it continues into the next line. This plays much nicer with left-right and top-down progressing of the default cursor movement.
But that is a major rewrite and we are in a state, where our more complicated abstraction works "good enough" - haha.
There was a problem hiding this comment.
FWIW, the LogicalLine re-write makes it trivial to implement a isWrapping (read-only) property, which is true when a line continues into the next line:
public get isWrapping(): boolean {
return !!this.nextBufferLine;
}
| if (nextLine && lastChar) { | ||
| nextLine.isWrapped = (lastChar[CHAR_DATA_CODE_INDEX] !== NULL_CELL_CODE && lastChar[CHAR_DATA_CODE_INDEX] !== WHITESPACE_CELL_CODE); | ||
| if (lastChar) { | ||
| bufferService.buffer.setWrapped(bufferService.buffer.ybase + bufferService.buffer.y, lastChar[CHAR_DATA_CODE_INDEX] !== NULL_CELL_CODE && lastChar[CHAR_DATA_CODE_INDEX] !== WHITESPACE_CELL_CODE); |
There was a problem hiding this comment.
This looks like a really hackish assumption over data state and def. will wrongly merge lines, that happened to end on the last cell and had a hard break following. (no critic on your code, I see that you just transformed it)
There was a problem hiding this comment.
Yes, I haven't really thought about this, but I followed the existing logic.
Though only for internal use (and only used twice), it could lead to improper use, even if not available in IBufferLine. Instead, change _isWrapped directly after a cast to any - that makes it more obvious we're tweaking internals.
| const line = this.lines.get(absrow); | ||
| line instanceof BufferLine && line.setWrapped(value); | ||
| (line as any)._isWrapped = value; |
There was a problem hiding this comment.
This looks now like it will throw, if get() returns undefined? I think the truthiness check will be needed, as get may return nothing.
Also the as any is not good, as will swallow lit. anything. Imho it is better to add _isWrapped to the interface type the ring buffer returns. This makes the later rework bark loud, once that flag vanishes - so we will miss places, where is needs to be fixed.
There was a problem hiding this comment.
Replaced the truthiness check, and avoided the as any. Instead, make _isWrapped public in BufferLine (but not IBufferLine), with some wrong warnings.
| newLine = buffer.getBlankLine(eraseAttr, isWrapped); | ||
| this._cachedBlankLine = newLine; | ||
| } else { | ||
| (newLine as any)._isWrapped = isWrapped; |
Instead, make _isWrapped public in BufferLine - but add strong warnings.
Having a publicly-writable
isWrappedproperty inBufferLinerestricts our implementation options for how wrapped lines are represented in aBuffer. For example, it conflicts with the proposal in #5673.To hide this implementation choice, this PR makes
isWrappedread-only, and adds aBuffer.setWrappedmethod (taking an absolute row number) for modifying theisWrappedstate. There is also an internal-onlyBufferLine.setWrappedmethod used to implementBuffer.setWrappedand in one other place.This gives greater flexibility in how BufferLine and line-wrapping are implemented.
This is likely to trivially conflict with PR #5785. If one of these is merged, I'll update the other one to fix any conflicts.