From 9bd850315279a99164d75ba73dc76571f6fd3255 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 20 Apr 2016 11:36:42 +0200 Subject: [PATCH 01/10] Use new DisplayLayer APIs --- lib/mixins/canvas-drawer.js | 88 ++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/lib/mixins/canvas-drawer.js b/lib/mixins/canvas-drawer.js index 15d41ce8..54ab9f17 100644 --- a/lib/mixins/canvas-drawer.js +++ b/lib/mixins/canvas-drawer.js @@ -401,6 +401,36 @@ export default class CanvasDrawer extends Mixin { renderData.context.fill() } + + tokenLinesForScreenRows (startRow, endRow) { + const displayLayer = this.getTextEditor().displayLayer + const invisibleRegExp = this.getInvisibleRegExp() + const screenLines = displayLayer.getScreenLines(startRow, endRow) + let tokenLines = [] + for (let {lineText, tagCodes} of screenLines) { + let tokens = [] + let scopes = [] + let textIndex = 0 + for (let tagCode of tagCodes) { + if (displayLayer.isOpenTagCode(tagCode)) { + scopes.push(displayLayer.tagForCode(tagCode)) + } else if (displayLayer.isCloseTagCode(tagCode)) { + scopes.pop() + } else { + tokens.push({ + text: lineText.substr(textIndex, tagCode).replace(invisibleRegExp, ' '), + scopes: scopes.slice() + }) + textIndex += tagCode + } + } + + tokenLines.push(tokens) + } + + return tokenLines + } + /** * Draws lines on the corresponding layer. * @@ -417,7 +447,6 @@ export default class CanvasDrawer extends Mixin { if (firstRow > lastRow) { return } const devicePixelRatio = this.minimap.getDevicePixelRatio() - const lines = this.getTextEditor().tokenizedLinesForScreenRows(firstRow, lastRow) const lineHeight = this.minimap.getLineHeight() * devicePixelRatio const charHeight = this.minimap.getCharHeight() * devicePixelRatio const charWidth = this.minimap.getCharWidth() * devicePixelRatio @@ -425,34 +454,16 @@ export default class CanvasDrawer extends Mixin { const context = this.tokensLayer.context const {width: canvasWidth} = this.tokensLayer.getSize() - let line = lines[0] - const invisibleRegExp = this.getInvisibleRegExp(line) - - for (let i = 0, len = lines.length; i < len; i++) { - line = lines[i] - const yRow = (offsetRow + i) * lineHeight + let y = offsetRow * lineHeight + for (let tokens of this.tokenLinesForScreenRows(firstRow, lastRow)) { let x = 0 - - if ((line != null ? line.tokens : void 0) != null) { - const tokens = line.tokens - for (let j = 0, tokensCount = tokens.length; j < tokensCount; j++) { - const token = tokens[j] - const w = token.screenDelta - if (!token.isOnlyWhitespace()) { - const color = displayCodeHighlights ? this.getTokenColor(token) : this.getDefaultColor() - - let value = token.value - if (invisibleRegExp != null) { - value = value.replace(invisibleRegExp, ' ') - } - x = this.drawToken(context, value, color, x, yRow, charWidth, charHeight) - } else { - x += w * charWidth - } - - if (x > canvasWidth) { break } - } + for (let token of tokens) { + const color = displayCodeHighlights ? this.getTokenColor(token) : this.getDefaultColor() + x = this.drawToken(context, token.text, color, x, y, charWidth, charHeight) + if (x > canvasWidth) { break } } + + y += lineHeight } context.fill() @@ -462,23 +473,18 @@ export default class CanvasDrawer extends Mixin { * Returns the regexp to replace invisibles substitution characters * in editor lines. * - * @param {TokenizedLine} line a tokenized lize to read the invisible - * characters * @return {RegExp} the regular expression to match invisible characters * @access private */ - getInvisibleRegExp (line) { - if ((line != null) && (line.invisibles != null)) { - const invisibles = [] - if (line.invisibles.cr != null) { invisibles.push(line.invisibles.cr) } - if (line.invisibles.eol != null) { invisibles.push(line.invisibles.eol) } - if (line.invisibles.space != null) { invisibles.push(line.invisibles.space) } - if (line.invisibles.tab != null) { invisibles.push(line.invisibles.tab) } - - return RegExp(invisibles.filter((s) => { - return typeof s === 'string' - }).map(_.escapeRegExp).join('|'), 'g') - } + getInvisibleRegExp () { + let invisibles = this.getTextEditor().getInvisibles() + let regexp = '' + if (invisibles.cr != null) { regexp += invisibles.cr + '|' } + if (invisibles.eol != null) { regexp += invisibles.eol + '|' } + if (invisibles.space != null) { regexp += invisibles.space + '|' } + if (invisibles.tab != null) { regexp += invisibles.tab + '|' } + + return new RegExp(_.escapeRegExp(regexp.slice(0, -1)), 'g') } /** From 0a62fb0e42456d23b4e468a3d8cbdc306ecd2205 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 20 Apr 2016 11:52:25 +0200 Subject: [PATCH 02/10] :fire: Remove deprecated APIs --- lib/adapters/legacy-adapter.js | 2 +- lib/minimap.js | 2 +- lib/mixins/decoration-management.js | 2 +- spec/minimap-spec.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/adapters/legacy-adapter.js b/lib/adapters/legacy-adapter.js index 37dc4a27..b7063bfe 100644 --- a/lib/adapters/legacy-adapter.js +++ b/lib/adapters/legacy-adapter.js @@ -63,7 +63,7 @@ export default class LegacyAdater { if (this.maxScrollTopCache != null && this.useCache) { return this.maxScrollTopCache } - var maxScrollTop = this.textEditor.displayBuffer.getMaxScrollTop() + var maxScrollTop = this.textEditor.getMaxScrollTop() var lineHeight = this.textEditor.getLineHeightInPixels() if (this.scrollPastEnd) { diff --git a/lib/minimap.js b/lib/minimap.js index eb986d38..13216dc2 100644 --- a/lib/minimap.js +++ b/lib/minimap.js @@ -232,7 +232,7 @@ export default class Minimap { resulting in extra lines appearing at the end of the minimap. Forcing a whole repaint to fix that bug is suboptimal but works. */ - subs.add(this.textEditor.displayBuffer.onDidTokenize(() => { + subs.add(this.textEditor.tokenizedBuffer.onDidTokenize(() => { this.emitter.emit('did-change-config') })) } diff --git a/lib/mixins/decoration-management.js b/lib/mixins/decoration-management.js index 2fa1b629..f288a91a 100644 --- a/lib/mixins/decoration-management.js +++ b/lib/mixins/decoration-management.js @@ -472,7 +472,7 @@ export default class DecorationManagement extends Mixin { * @access private */ emitDecorationChanges (type, decoration) { - if (decoration.marker.displayBuffer.isDestroyed()) { return } + if (decoration.marker.isDestroyed()) { return } this.invalidateDecorationForScreenRowsCache() diff --git a/spec/minimap-spec.js b/spec/minimap-spec.js index 5381410c..de3ee864 100644 --- a/spec/minimap-spec.js +++ b/spec/minimap-spec.js @@ -120,7 +120,7 @@ describe('Minimap', () => { it('adjust the scrolling ratio', () => { editorElement.setScrollTop(editorElement.getScrollHeight()) - let maxScrollTop = editorElement.getScrollHeight() - editorElement.getHeight() - (editorElement.getHeight() - 3 * editor.displayBuffer.getLineHeightInPixels()) + let maxScrollTop = editorElement.getScrollHeight() - editorElement.getHeight() - (editorElement.getHeight() - 3 * editor.getLineHeightInPixels()) expect(minimap.getTextEditorScrollRatio()).toEqual(editorElement.getScrollTop() / maxScrollTop) }) From 1a702c9190b9f00bc5049d4fad871ae3f2e7e98b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 20 Apr 2016 12:04:15 +0200 Subject: [PATCH 03/10] Make change backwards-compatible --- lib/mixins/canvas-drawer.js | 50 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/lib/mixins/canvas-drawer.js b/lib/mixins/canvas-drawer.js index 54ab9f17..dfb71d4d 100644 --- a/lib/mixins/canvas-drawer.js +++ b/lib/mixins/canvas-drawer.js @@ -403,31 +403,37 @@ export default class CanvasDrawer extends Mixin { } tokenLinesForScreenRows (startRow, endRow) { - const displayLayer = this.getTextEditor().displayLayer - const invisibleRegExp = this.getInvisibleRegExp() - const screenLines = displayLayer.getScreenLines(startRow, endRow) + const editor = this.getTextEditor() let tokenLines = [] - for (let {lineText, tagCodes} of screenLines) { - let tokens = [] - let scopes = [] - let textIndex = 0 - for (let tagCode of tagCodes) { - if (displayLayer.isOpenTagCode(tagCode)) { - scopes.push(displayLayer.tagForCode(tagCode)) - } else if (displayLayer.isCloseTagCode(tagCode)) { - scopes.pop() - } else { - tokens.push({ - text: lineText.substr(textIndex, tagCode).replace(invisibleRegExp, ' '), - scopes: scopes.slice() - }) - textIndex += tagCode - } + if (typeof editor.tokenizedLinesForScreenRows === "function") { + for (let tokenizedLine of editor.tokenizedLinesForScreenRows(startRow, endRow)) { + tokenLines.push(tokenizedLine.tokens) } + } else { + const displayLayer = editor.displayLayer + const invisibleRegExp = this.getInvisibleRegExp() + const screenLines = displayLayer.getScreenLines(startRow, endRow) + for (let {lineText, tagCodes} of screenLines) { + let tokens = [] + let scopes = [] + let textIndex = 0 + for (let tagCode of tagCodes) { + if (displayLayer.isOpenTagCode(tagCode)) { + scopes.push(displayLayer.tagForCode(tagCode)) + } else if (displayLayer.isCloseTagCode(tagCode)) { + scopes.pop() + } else { + tokens.push({ + value: lineText.substr(textIndex, tagCode).replace(invisibleRegExp, ' '), + scopes: scopes.slice() + }) + textIndex += tagCode + } + } - tokenLines.push(tokens) + tokenLines.push(tokens) + } } - return tokenLines } @@ -459,7 +465,7 @@ export default class CanvasDrawer extends Mixin { let x = 0 for (let token of tokens) { const color = displayCodeHighlights ? this.getTokenColor(token) : this.getDefaultColor() - x = this.drawToken(context, token.text, color, x, y, charWidth, charHeight) + x = this.drawToken(context, token.value, color, x, y, charWidth, charHeight) if (x > canvasWidth) { break } } From aff85c02f1f0e333115eeccb58938390c74b327d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 20 Apr 2016 12:11:42 +0200 Subject: [PATCH 04/10] :shirt: Sorry, linter. --- lib/mixins/canvas-drawer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mixins/canvas-drawer.js b/lib/mixins/canvas-drawer.js index dfb71d4d..5f7dd65b 100644 --- a/lib/mixins/canvas-drawer.js +++ b/lib/mixins/canvas-drawer.js @@ -405,7 +405,7 @@ export default class CanvasDrawer extends Mixin { tokenLinesForScreenRows (startRow, endRow) { const editor = this.getTextEditor() let tokenLines = [] - if (typeof editor.tokenizedLinesForScreenRows === "function") { + if (typeof editor.tokenizedLinesForScreenRows === 'function') { for (let tokenizedLine of editor.tokenizedLinesForScreenRows(startRow, endRow)) { tokenLines.push(tokenizedLine.tokens) } From a7b99d3575d102ac9475dee4f799bfaf6cb4215d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 20 Apr 2016 12:21:19 +0200 Subject: [PATCH 05/10] :green_heart --- lib/minimap.js | 3 ++- lib/mixins/decoration-management.js | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/minimap.js b/lib/minimap.js index 13216dc2..bce79d0a 100644 --- a/lib/minimap.js +++ b/lib/minimap.js @@ -232,7 +232,8 @@ export default class Minimap { resulting in extra lines appearing at the end of the minimap. Forcing a whole repaint to fix that bug is suboptimal but works. */ - subs.add(this.textEditor.tokenizedBuffer.onDidTokenize(() => { + let tokenizedBuffer = this.textEditor.tokenizedBuffer ? this.textEditor.tokenizedBuffer : this.textEditor.displayBuffer.tokenizedBuffer + subs.add(tokenizedBuffer.onDidTokenize(() => { this.emitter.emit('did-change-config') })) } diff --git a/lib/mixins/decoration-management.js b/lib/mixins/decoration-management.js index f288a91a..02b3c01d 100644 --- a/lib/mixins/decoration-management.js +++ b/lib/mixins/decoration-management.js @@ -472,8 +472,6 @@ export default class DecorationManagement extends Mixin { * @access private */ emitDecorationChanges (type, decoration) { - if (decoration.marker.isDestroyed()) { return } - this.invalidateDecorationForScreenRowsCache() let range = decoration.marker.getScreenRange() From 64ef015a8bbddac27682281525508d3d24e0b75d Mon Sep 17 00:00:00 2001 From: abe33 Date: Wed, 20 Apr 2016 20:04:31 +0200 Subject: [PATCH 06/10] :bug: Fix invisible characters not replaced without display layer enabled --- lib/mixins/canvas-drawer.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/mixins/canvas-drawer.js b/lib/mixins/canvas-drawer.js index 5f7dd65b..145955c3 100644 --- a/lib/mixins/canvas-drawer.js +++ b/lib/mixins/canvas-drawer.js @@ -407,7 +407,13 @@ export default class CanvasDrawer extends Mixin { let tokenLines = [] if (typeof editor.tokenizedLinesForScreenRows === 'function') { for (let tokenizedLine of editor.tokenizedLinesForScreenRows(startRow, endRow)) { - tokenLines.push(tokenizedLine.tokens) + const invisibleRegExp = this.getInvisibleRegExpForLine(tokenizedLine) + tokenLines.push(tokenizedLine.tokens.map((token) => { + return { + value: token.value.replace(invisibleRegExp, ' '), + scopes: token.scopes.slice() + } + })) } } else { const displayLayer = editor.displayLayer @@ -493,6 +499,20 @@ export default class CanvasDrawer extends Mixin { return new RegExp(_.escapeRegExp(regexp.slice(0, -1)), 'g') } + getInvisibleRegExpForLine (line) { + if ((line != null) && (line.invisibles != null)) { + const invisibles = [] + if (line.invisibles.cr != null) { invisibles.push(line.invisibles.cr) } + if (line.invisibles.eol != null) { invisibles.push(line.invisibles.eol) } + if (line.invisibles.space != null) { invisibles.push(line.invisibles.space) } + if (line.invisibles.tab != null) { invisibles.push(line.invisibles.tab) } + + return RegExp(invisibles.filter((s) => { + return typeof s === 'string' + }).map(_.escapeRegExp).join('|'), 'g') + } + } + /** * Draws a single token on the given context. * From 359a30c0d334fdb79b9d9e973b382a7e88b09d5f Mon Sep 17 00:00:00 2001 From: abe33 Date: Wed, 20 Apr 2016 20:05:04 +0200 Subject: [PATCH 07/10] :racehorse: No need to paint tokens with only whitespaces --- lib/mixins/canvas-drawer.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/mixins/canvas-drawer.js b/lib/mixins/canvas-drawer.js index 145955c3..06b014e0 100644 --- a/lib/mixins/canvas-drawer.js +++ b/lib/mixins/canvas-drawer.js @@ -470,8 +470,12 @@ export default class CanvasDrawer extends Mixin { for (let tokens of this.tokenLinesForScreenRows(firstRow, lastRow)) { let x = 0 for (let token of tokens) { - const color = displayCodeHighlights ? this.getTokenColor(token) : this.getDefaultColor() - x = this.drawToken(context, token.value, color, x, y, charWidth, charHeight) + if (/^\s+$/.test(token.value)) { + x += token.value.length * charWidth + } else { + const color = displayCodeHighlights ? this.getTokenColor(token) : this.getDefaultColor() + x = this.drawToken(context, token.value, color, x, y, charWidth, charHeight) + } if (x > canvasWidth) { break } } From b7b0a3b71e498dee4880f6b830189139cab2c10b Mon Sep 17 00:00:00 2001 From: abe33 Date: Wed, 20 Apr 2016 20:09:54 +0200 Subject: [PATCH 08/10] :memo: Add docs comment on new functions --- lib/mixins/canvas-drawer.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/mixins/canvas-drawer.js b/lib/mixins/canvas-drawer.js index 06b014e0..1640776d 100644 --- a/lib/mixins/canvas-drawer.js +++ b/lib/mixins/canvas-drawer.js @@ -402,6 +402,14 @@ export default class CanvasDrawer extends Mixin { renderData.context.fill() } + /** + * Returns an array of tokens by line. + * + * @param {number} startRow The start row + * @param {number} endRow The end row + * @return {Array} An array of tokens by line + * @access private + */ tokenLinesForScreenRows (startRow, endRow) { const editor = this.getTextEditor() let tokenLines = [] @@ -503,6 +511,15 @@ export default class CanvasDrawer extends Mixin { return new RegExp(_.escapeRegExp(regexp.slice(0, -1)), 'g') } + /** + * Returns the regexp to replace invisibles substitution characters + * in editor lines. + * + * @param {Object} line the tokenized line + * @return {RegExp} the regular expression to match invisible characters + * @deprecated Is used only to support Atom version before display layer API + * @access private + */ getInvisibleRegExpForLine (line) { if ((line != null) && (line.invisibles != null)) { const invisibles = [] From 4fe360f51c38dabfa0e974c21d835dcd611d3267 Mon Sep 17 00:00:00 2001 From: abe33 Date: Thu, 21 Apr 2016 19:56:53 +0200 Subject: [PATCH 09/10] :bug: Fix missing lines when scrolling up --- lib/mixins/canvas-drawer.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/mixins/canvas-drawer.js b/lib/mixins/canvas-drawer.js index 1640776d..cd35a9f8 100644 --- a/lib/mixins/canvas-drawer.js +++ b/lib/mixins/canvas-drawer.js @@ -300,7 +300,7 @@ export default class CanvasDrawer extends Mixin { for (let i = 0, len = ranges.length; i < len; i++) { const range = ranges[i] - method.call(this, currentRow, range.start - 1, currentRow - firstRow) + method.call(this, currentRow, range.start, currentRow - firstRow) currentRow = range.end } @@ -477,6 +477,7 @@ export default class CanvasDrawer extends Mixin { let y = offsetRow * lineHeight for (let tokens of this.tokenLinesForScreenRows(firstRow, lastRow)) { let x = 0 + context.clearRect(x, y, canvasWidth, lineHeight) for (let token of tokens) { if (/^\s+$/.test(token.value)) { x += token.value.length * charWidth @@ -593,6 +594,11 @@ export default class CanvasDrawer extends Mixin { drawDecorations (screenRow, decorations, renderData, types) { let decorationsToRender = [] + renderData.context.clearRect( + 0, renderData.yRow, + renderData.canvasWidth, renderData.lineHeight + ) + for (let i in types) { decorationsToRender = decorationsToRender.concat( decorations[i] != null ? decorations[i][screenRow] || [] : [] From c3a13761f734a829baac91a6a536a81d71ed3074 Mon Sep 17 00:00:00 2001 From: abe33 Date: Thu, 21 Apr 2016 20:19:45 +0200 Subject: [PATCH 10/10] :green_heart: Fix broken test --- spec/minimap-element-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/minimap-element-spec.js b/spec/minimap-element-spec.js index cc7de432..319b0624 100644 --- a/spec/minimap-element-spec.js +++ b/spec/minimap-element-spec.js @@ -518,7 +518,7 @@ describe('MinimapElement', () => { expect(minimapElement.drawLines).toHaveBeenCalled() expect(minimapElement.drawLines.argsForCall[0][0]).toEqual(100) - expect(minimapElement.drawLines.argsForCall[0][1]).toEqual(101) + expect(minimapElement.drawLines.argsForCall[0][1]).toEqual(102) }) }) })