| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -106,7 +106,8 @@ class TermScreen { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      blinkStyleOn: true, | 
					 | 
					 | 
					 | 
					      blinkStyleOn: true, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      blinkInterval: null, | 
					 | 
					 | 
					 | 
					      blinkInterval: null, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      fitIntoWidth: 0, | 
					 | 
					 | 
					 | 
					      fitIntoWidth: 0, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      fitIntoHeight: 0 | 
					 | 
					 | 
					 | 
					      fitIntoHeight: 0, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      debug: false | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // properties of this.window that require updating size and redrawing
 | 
					 | 
					 | 
					 | 
					    // properties of this.window that require updating size and redrawing
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -665,20 +666,20 @@ class TermScreen { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ctx.globalAlpha = 1 | 
					 | 
					 | 
					 | 
					    ctx.globalAlpha = 1 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  getAdjacentCells (cell) { | 
					 | 
					 | 
					 | 
					  getAdjacentCells (cell, radius = 1) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const { width, height } = this.window | 
					 | 
					 | 
					 | 
					    const { width, height } = this.window | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const screenLength = width * height | 
					 | 
					 | 
					 | 
					    const screenLength = width * height | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    return [ | 
					 | 
					 | 
					 | 
					    let cells = [] | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      cell - 1, | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      cell + 1, | 
					 | 
					 | 
					 | 
					    for (let x = -radius; x <= radius; x++) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      cell - width, | 
					 | 
					 | 
					 | 
					      for (let y = -radius; y <= radius; y++) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      cell + width, | 
					 | 
					 | 
					 | 
					        if (x === 0 && y === 0) continue | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      cell - width - 1, | 
					 | 
					 | 
					 | 
					        cells.push(cell + x + y * width) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      cell - width + 1, | 
					 | 
					 | 
					 | 
					      } | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      cell + width - 1, | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      cell + width + 1 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ].filter(adjacentCell => adjacentCell >= 0 && adjacentCell < screenLength) | 
					 | 
					 | 
					 | 
					    return cells.filter(cell => cell >= 0 && cell < screenLength) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  } | 
					 | 
					 | 
					 | 
					  } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  draw () { | 
					 | 
					 | 
					 | 
					  draw () { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -699,6 +700,12 @@ class TermScreen { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0) | 
					 | 
					 | 
					 | 
					    ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    if (this.window.debug) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      // differentiate static cells from updated cells
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      ctx.fillStyle = 'rgba(255, 0, 255, 0.3)' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      ctx.fillRect(0, 0, screenWidth, screenHeight) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ctx.font = this.getFont() | 
					 | 
					 | 
					 | 
					    ctx.font = this.getFont() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ctx.textAlign = 'center' | 
					 | 
					 | 
					 | 
					    ctx.textAlign = 'center' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ctx.textBaseline = 'middle' | 
					 | 
					 | 
					 | 
					    ctx.textBaseline = 'middle' | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -753,16 +760,23 @@ class TermScreen { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Map of (cell index) -> boolean, whether or not a cell should be redrawn
 | 
					 | 
					 | 
					 | 
					    // Map of (cell index) -> boolean, whether or not a cell should be redrawn
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    const redrawMap = new Map() | 
					 | 
					 | 
					 | 
					    const redrawMap = new Map() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    let isTextWide = text => | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      text !== ' ' && ctx.measureText(text).width >= (cellWidth + 0.05) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // decide for each cell if it should be redrawn
 | 
					 | 
					 | 
					 | 
					    // decide for each cell if it should be redrawn
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    let updateRedrawMapAt = cell => { | 
					 | 
					 | 
					 | 
					    let updateRedrawMapAt = cell => { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      let shouldUpdate = updateMap.get(cell) || redrawMap.get(cell) | 
					 | 
					 | 
					 | 
					      let shouldUpdate = updateMap.get(cell) || redrawMap.get(cell) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      let adjacentCells = this.getAdjacentCells(cell) | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      // TODO: fonts (necessary?)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      let text = this.screen[cell] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      let isWideCell = isTextWide(text) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					      let checkRadius = isWideCell ? 2 : 1 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (!shouldUpdate) { | 
					 | 
					 | 
					 | 
					      if (!shouldUpdate) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // check adjacent cells
 | 
					 | 
					 | 
					 | 
					        // check adjacent cells
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        let adjacentDidUpdate = false | 
					 | 
					 | 
					 | 
					        let adjacentDidUpdate = false | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        for (let adjacentCell of adjacentCells) { | 
					 | 
					 | 
					 | 
					        for (let adjacentCell of this.getAdjacentCells(cell, checkRadius)) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          if (updateMap.get(adjacentCell)) { | 
					 | 
					 | 
					 | 
					          if (updateMap.get(adjacentCell)) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            adjacentDidUpdate = true | 
					 | 
					 | 
					 | 
					            adjacentDidUpdate = true | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            break | 
					 | 
					 | 
					 | 
					            break | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -773,14 +787,9 @@ class TermScreen { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      } | 
					 | 
					 | 
					 | 
					      } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					      if (shouldUpdate) { | 
					 | 
					 | 
					 | 
					      if (shouldUpdate) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // TODO: fonts (necessary?)
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        let text = this.screen[cell] | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        let isWideCell = ctx.measureText(text).width >= cellWidth | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (text === ' ') isWideCell = false | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (isWideCell) { | 
					 | 
					 | 
					 | 
					        if (isWideCell) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          // set redraw for adjacent cells
 | 
					 | 
					 | 
					 | 
					          // set redraw for adjacent cells
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          for (let adjacentCell of adjacentCells) { | 
					 | 
					 | 
					 | 
					          for (let adjacentCell of this.getAdjacentCells(cell)) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            redrawMap.set(adjacentCell, true) | 
					 | 
					 | 
					 | 
					            redrawMap.set(adjacentCell, true) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          } | 
					 | 
					 | 
					 | 
					          } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -788,7 +797,7 @@ class TermScreen { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          let index = cell - 1 | 
					 | 
					 | 
					 | 
					          let index = cell - 1 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          while (index > 0) { | 
					 | 
					 | 
					 | 
					          while (index > 0) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            let text = this.screen[index] | 
					 | 
					 | 
					 | 
					            let text = this.screen[index] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            let isWide = ctx.measureText(text).width >= cellWidth && text !== ' ' | 
					 | 
					 | 
					 | 
					            let isWide = isTextWide(text) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            if (redrawMap.get(index - 1)) break | 
					 | 
					 | 
					 | 
					            if (redrawMap.get(index - 1)) break | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -839,6 +848,18 @@ class TermScreen { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          this.drawnScreenFG[cell] = fg | 
					 | 
					 | 
					 | 
					          this.drawnScreenFG[cell] = fg | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          this.drawnScreenBG[cell] = bg | 
					 | 
					 | 
					 | 
					          this.drawnScreenBG[cell] = bg | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					          this.drawnScreenAttrs[cell] = attrs | 
					 | 
					 | 
					 | 
					          this.drawnScreenAttrs[cell] = attrs | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          if (this.window.debug) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            // add cell data
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ctx.save() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ctx.fillStyle = '#0f0' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ctx.font = '6px monospace' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ctx.textAlign = 'left' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ctx.textBaseline = 'top' | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ctx.fillText(+isTextWide(text), x * cellWidth, y * cellHeight) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ctx.fillText(+updateMap.get(cell), x * cellWidth, y * cellHeight + 6) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            ctx.restore() | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					          } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        } | 
					 | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (isCursor && this.cursor.blinkOn && this.cursor.style !== 'block') { | 
					 | 
					 | 
					 | 
					        if (isCursor && this.cursor.blinkOn && this.cursor.style !== 'block') { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
  |