Skip to content
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

consider proportional font char width #656

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 31 additions & 42 deletions lib/mixins/canvas-drawer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict'

const _ = require('underscore-plus')
const Mixin = require('mixto')
const Main = require('../main')
const CanvasLayer = require('../canvas-layer')
Expand Down Expand Up @@ -402,6 +401,23 @@ module.exports = class CanvasDrawer extends Mixin {
renderData.context.fill()
}

textSizeOnEditor (editor, text, ch = '0') {
const view = atom.views.getView(editor)
const node = document.createElement('div')
node.textContent = ch
node.style.whiteSpace = 'pre'
view.append(node)
const reference = node.getBoundingClientRect().width
const sizes = []
for (const segment of text.split(/(\s+)/u)) {
node.textContent = segment
sizes.push(node.getBoundingClientRect().width / reference)
}
node.remove()

return sizes
}

/**
* Returns an array of tokens by line.
*
Expand All @@ -412,13 +428,12 @@ module.exports = class CanvasDrawer extends Mixin {
*/
eachTokenForScreenRows (startRow, endRow, callback) {
const editor = this.getTextEditor()
const invisibleRegExp = this.getInvisibleRegExp()
endRow = Math.min(endRow, editor.getScreenLineCount())

for (let row = startRow; row < endRow; row++) {
editor.tokensForScreenRow(row).forEach(token => {
callback(row, {
text: token.text.replace(invisibleRegExp, ' '),
sizes: this.textSizeOnEditor(editor, token.text),
scopes: token.scopes
})
})
Expand Down Expand Up @@ -459,41 +474,21 @@ module.exports = class CanvasDrawer extends Mixin {
}
if (x > canvasWidth) { return }

if (/^\s+$/.test(token.text)) {
x += token.text.length * charWidth
if (token.scopes.map(scope => scope.split(' ')).reduce((a, b) => [...a, ...b], []).includes('invisible-character')) {
x += token.sizes.reduce((a, b) => a + b) * charWidth
} else {
const color = displayCodeHighlights
? this.getTokenColor(token)
: this.getDefaultColor()

x = this.drawToken(
context, token.text, color, x, y, charWidth, charHeight
context, token.sizes, color, x, y, charWidth, charHeight
)
}
})
context.fill()
}

/**
* Returns the regexp to replace invisibles substitution characters
* in editor lines.
*
* @return {RegExp} the regular expression to match invisible characters
* @access private
*/
getInvisibleRegExp () {
let invisibles = this.getTextEditor().getInvisibles()
let regexp = []
if (invisibles.cr != null) { regexp.push(invisibles.cr) }
if (invisibles.eol != null) { regexp.push(invisibles.eol) }
if (invisibles.space != null) { regexp.push(invisibles.space) }
if (invisibles.tab != null) { regexp.push(invisibles.tab) }

return regexp.length === 0 ? null : RegExp(regexp.filter((s) => {
return typeof s === 'string'
}).map(_.escapeRegExp).join('|'), 'g')
}

/**
* Draws a single token on the given context.
*
Expand All @@ -507,30 +502,24 @@ module.exports = class CanvasDrawer extends Mixin {
* @return {number} the x position at the end of the token
* @access private
*/
drawToken (context, text, color, x, y, charWidth, charHeight) {
drawToken (context, sizes, color, x, y, charWidth, charHeight) {
context.fillStyle = color

if (this.ignoreWhitespacesInTokens) {
const length = text.length * charWidth
const sum = sizes.reduce((a, b) => a + b)
const length = sum * charWidth
context.fillRect(x, y, length, charHeight)

return x + length
} else {
let chars = 0
for (let j = 0, len = text.length; j < len; j++) {
const char = text[j]
if (/\s/.test(char)) {
if (chars > 0) {
context.fillRect(x - (chars * charWidth), y, chars * charWidth, charHeight)
}
chars = 0
} else {
chars++
let w = true
for (const size of sizes) {
const width = size * charWidth
if (w) {
context.fillRect(x, y, width, charHeight)
}
x += charWidth
}
if (chars > 0) {
context.fillRect(x - (chars * charWidth), y, chars * charWidth, charHeight)
w = !w
x += width
}
return x
}
Expand Down