bricks-cli
Version:
Command line tool for developing ambitious ember.js apps
265 lines (246 loc) • 7.15 kB
JavaScript
/*
appview.js
==========
The actual AppView. This encapsulates the entire UI.
*/
var View = require('./view')
var tabs = require('./runner_tabs')
var constants = require('./constants')
var RunnerTab = tabs.RunnerTab
var RunnerTabs = tabs.RunnerTabs
var Screen = require('./screen')
var pad = require('../../strutils').pad
var log = require('npmlog')
var ErrorMessagesPanel = require('./error_messages_panel')
var setRawMode = process.stdin.setRawMode ?
function(bool){ process.stdin.setRawMode(bool) } :
require('tty').setRawMode
var AppView = module.exports = View.extend({
defaults: {
currentTab: 0
, atLeastOneRunner: false
}
, initialize: function(attrs){
var app = attrs.app
this.name = 'Testem'
this.app = app
this.config = app.config
if (!this.get('screen')){
this.set('screen', Screen())
}
this.initCharm()
var screen = this.get('screen')
var runnerTabs = this.runnerTabs = new RunnerTabs([], {
appview: this
, screen: screen
})
this.set({
runnerTabs: runnerTabs
})
var self = this
var runners = this.runners()
runners.on('add', function(runner, options){
var idx = options.index || runners.length - 1
var tab = new RunnerTab({
runner: runner
, index: idx
, appview: self
, screen: screen
})
runnerTabs.push(tab)
})
runners.on('add remove', function(){
self.set('atLeastOneRunner', runners.length > 0)
})
runnerTabs.on('add', function(){
runnerTabs.render()
})
this.on('change:atLeastOneRunner', function(atLeastOne){
if (atLeastOne && self.get('currentTab') < 0){
self.set('currentTab', 0)
}
self.renderMiddle()
self.renderBottom()
})
this.on('change:lines change:cols', function(){
self.render()
})
this.errorMessagesPanel = new ErrorMessagesPanel({
appview: this
, text: ''
, screen: screen
})
this.errorMessagesPanel.on('change:text', function(m, text){
self.set('isPopupVisible', !!text)
})
this.startMonitorTermSize()
}
, initCharm: function(){
var screen = this.get('screen')
screen.reset()
screen.erase('screen')
screen.cursor(false)
screen.on('data', this.onInputChar.bind(this))
screen.on('^C', function(buf){
this.trigger('ctrl-c')
}.bind(this))
}
, startMonitorTermSize: function(){
var self = this
var screen = self.get('screen')
this.updateScreenDimensions()
process.stdout.on('resize', function(){
var cols = process.stdout.columns
var lines = process.stdout.rows
if (cols !== self.get('cols') || lines !== self.get('lines')){
self.updateScreenDimensions()
}
})
},
updateScreenDimensions: function(){
var screen = this.get('screen')
var cols = process.stdout.columns
var lines = process.stdout.rows
screen.enableScroll(constants.LogPanelUnusedLines, lines - 1)
this.set({
cols: cols
, lines: lines
})
this.updateErrorMessagesPanelSize()
}
, updateErrorMessagesPanelSize: function(){
this.errorMessagesPanel.set({
line: 2
, col: 4
, width: this.get('cols') - 8
, height: this.get('lines') - 4
})
}
, render: function(){
this.renderTop()
if (!this.get('atLeastOneRunner')){
this.renderMiddle()
}
this.renderBottom()
}
, renderTop: function(){
if (this.isPopupVisible()) return
var screen = this.get('screen')
var url = this.config.get('url')
var cols = this.get('cols')
screen
.position(0, 1)
.write(pad('TEST\u0027EM \u0027SCRIPTS!', cols, ' ', 1))
.position(0, 2)
.write(pad('Open the URL below in a browser to connect.', cols, ' ', 1))
.position(0, 3)
.display('underscore')
.write(url, cols, ' ', 1)
.display('reset')
.position(url.length + 1, 3)
.write(pad('', cols - url.length, ' ', 1))
}
, renderMiddle: function(){
if (this.isPopupVisible()) return
if (this.runners.length > 0) return
var screen = this.get('screen')
var lines = this.get('lines')
var cols = this.get('cols')
var textLineIdx = Math.floor(lines / 2 + 2)
for (var i = constants.LogPanelUnusedLines; i < lines; i++){
var text = (i === textLineIdx ? 'Waiting for runners...' : '')
screen
.position(0, i)
.write(pad(text, cols, ' ', 2))
}
}
, renderBottom: function(){
if (this.isPopupVisible()) return
var screen = this.get('screen')
var cols = this.get('cols')
var msg = (
!this.get('atLeastOneRunner') ?
'[q to quit]' :
'[Press ENTER to run tests; q to quit]'
)
screen
.position(0, this.get('lines'))
.write(pad(msg, cols - 1, ' ', 1))
}
, runners: function(){
return this.app.runners
}
, currentRunnerTab: function(){
var idx = this.get('currentTab')
return this.runnerTabs.at(idx)
}
, onInputChar: function(buf){
try{
var chr = String(buf).charAt(0)
var i = chr.charCodeAt(0)
var key = (buf[0] === 27 && buf[1] === 91) ? buf[2] : null
var currentRunnerTab = this.currentRunnerTab()
var splitPanel = currentRunnerTab && currentRunnerTab.splitPanel
//log.info([buf[0], buf[1], buf[2]].join(','))
if (key === 67){ // right arrow
this.nextTab()
}else if (key === 68){ // left arrow
this.prevTab()
}else if (key === 66){ // down arrow
splitPanel.scrollDown()
}else if (key === 65){ // up arrow
splitPanel.scrollUp()
}else if (chr === '\t'){
splitPanel.toggleFocus()
}else if (chr === ' '){
splitPanel.pageDown()
}else if (chr === 'b'){
splitPanel.pageUp()
}else if (chr === 'u'){
splitPanel.halfPageUp()
}else if (chr === 'd'){
splitPanel.halfPageDown()
}
this.trigger('inputChar', chr, i)
}catch(e){
log.error('In onInputChar: ' + e + '\n' + e.stack)
}
}
, nextTab: function(){
var currentTab = this.get('currentTab')
currentTab++
if (currentTab >= this.runners().length)
currentTab = 0
var runner = this.runners().at(currentTab)
this.set('currentTab', currentTab)
}
, prevTab: function(){
var currentTab = this.get('currentTab')
currentTab--
if (currentTab < 0)
currentTab = this.runners().length - 1
var runner = this.runners().at(currentTab)
this.set('currentTab', currentTab)
}
, setErrorPopupMessage: function(msg){
this.errorMessagesPanel.set('text', msg)
}
, clearErrorPopupMessage: function(){
this.errorMessagesPanel.set('text', '')
this.render()
}
, isPopupVisible: function(){
return !! this.get('isPopupVisible')
}
, cleanup: function(cb){
var screen = this.get('screen')
screen.display('reset')
screen.erase('screen')
screen.position(0, 0)
screen.enableScroll()
screen.cursor(true)
setRawMode(false)
screen.destroy()
if (cb) cb()
}
})