-
Notifications
You must be signed in to change notification settings - Fork 16
feat: render terminals in the bottom dock #14
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,7 +91,7 @@ class StatusBar extends View { | |
} | ||
} else { | ||
this.setActiveTerminalView(nextTerminal) | ||
if (prevTerminal && prevTerminal.panel.isVisible()) { | ||
if ((prevTerminal && prevTerminal.panel.isVisible()) || atom.workspace.getBottomDock().isVisible()) { | ||
nextTerminal.toggle() | ||
} | ||
} | ||
|
@@ -397,8 +397,7 @@ class StatusBar extends View { | |
for (let i = this.terminalViews.length - 1; i >= 0; i--) { | ||
const view = this.terminalViews[i] | ||
if (view) { | ||
view.ptyProcess.terminate() | ||
view.terminal.destroy() | ||
view.destroy() | ||
} | ||
} | ||
this.detach() | ||
|
@@ -507,6 +506,7 @@ class StatusBar extends View { | |
|
||
const fromIndex = parseInt(dataTransfer.getData('from-index')) | ||
const view = this.terminalViews[fromIndex] | ||
if (!view) return | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. even with the terminals in the bottom panel, when moved, I see an error notification because
This comment was marked as resolved.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moving dock NOT panel theres an error. [Enter steps to reproduce:] Atom: 1.41.0 x64 Stack TraceUncaught TypeError: Cannot read property 'destroy' of undefined
Commands
Non-Core Packages
FYI this works without being on dock Without this PR its actually possible to move the terminal into the bottom dock even if docks arent implemented There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea the input button should be in the status bar while using the dock. I hadn't gotten to that yet. I think we should move forward with the strategy in #15 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That sounds good. =) |
||
view.css('height', '') | ||
view.terminal.element.style.height = atom.config.get('terminus.style.defaultPanelHeight') | ||
// const tabBar = $(event.target).closest('.tab-bar'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
const isString = x => typeof x === 'string' | ||
|
||
// visibility for items in bottom dock | ||
module.exports.isVisible = function (itemOrUri) { | ||
const uri = isString(itemOrUri) ? itemOrUri : itemOrUri.getURI() | ||
|
||
const dock = atom.workspace.getBottomDock() | ||
if (!dock.isVisible()) return false | ||
|
||
const activeItem = dock.getActivePaneItem() | ||
if (!activeItem) return false | ||
|
||
return activeItem.getURI && activeItem.getURI() === uri | ||
} | ||
|
||
module.exports.isUseDockEnabled = () => atom.config.get('terminus.toggles.useDock') |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ const { $, View } = require('atom-space-pen-views') | |
|
||
const Pty = require.resolve('./process') | ||
const Terminal = require('term.js') | ||
const { isUseDockEnabled, isVisible } = require('./utils') | ||
let InputDialog = null | ||
|
||
const path = require('path') | ||
|
@@ -11,6 +12,8 @@ const os = require('os') | |
let lastOpenedView = null | ||
let lastActiveElement = null | ||
|
||
let nextId = 0 | ||
|
||
class TerminusView extends View { | ||
static content () { | ||
this.div({ class: 'terminus terminal-view', outlet: 'terminusView' }, () => { | ||
|
@@ -20,11 +23,13 @@ class TerminusView extends View { | |
this.div({ class: 'btn-group' }, () => { | ||
this.button({ outlet: 'inputBtn', class: 'btn icon icon-keyboard', click: 'inputDialog' }) | ||
}) | ||
this.div({ class: 'btn-group right' }, () => { | ||
this.button({ outlet: 'hideBtn', class: 'btn icon icon-chevron-down', click: 'hide' }) | ||
this.button({ outlet: 'maximizeBtn', class: 'btn icon icon-screen-full', click: 'maximize' }) | ||
this.button({ outlet: 'closeBtn', class: 'btn icon icon-x', click: 'destroy' }) | ||
}) | ||
if (!isUseDockEnabled()) { | ||
this.div({ class: 'btn-group right' }, () => { | ||
this.button({ outlet: 'hideBtn', class: 'btn icon icon-chevron-down', click: 'hide' }) | ||
this.button({ outlet: 'maximizeBtn', class: 'btn icon icon-screen-full', click: 'maximize' }) | ||
this.button({ outlet: 'closeBtn', class: 'btn icon icon-x', click: 'destroy' }) | ||
}) | ||
} | ||
}) | ||
}) | ||
this.div({ class: 'xterm', outlet: 'xterm' }) | ||
|
@@ -35,7 +40,17 @@ class TerminusView extends View { | |
return Terminal.Terminal.focus | ||
} | ||
|
||
getURI () { return `atom://terminus/${this.viewId}` } | ||
|
||
getDefaultLocation () { return 'bottom' } | ||
|
||
getAllowedLocations () { return ['bottom'] } | ||
|
||
isPermanentDockItem () { return false } | ||
|
||
initialize (id, pwd, statusIcon, statusBar, shell, args = [], env = {}, autoRun = []) { | ||
this.shouldUseDock = isUseDockEnabled() | ||
if (this.shouldUseDock) { this.viewId = nextId++ } | ||
this.id = id | ||
this.pwd = pwd | ||
this.statusIcon = statusIcon | ||
|
@@ -56,24 +71,28 @@ class TerminusView extends View { | |
this.updateToolbarVisibility = this.updateToolbarVisibility.bind(this) | ||
this.recieveItemOrFile = this.recieveItemOrFile.bind(this) | ||
|
||
this.subscriptions.add(atom.tooltips.add(this.closeBtn, { title: 'Close' })) | ||
this.subscriptions.add(atom.tooltips.add(this.hideBtn, { title: 'Hide' })) | ||
this.subscriptions.add(this.maximizeBtn.tooltip = atom.tooltips.add(this.maximizeBtn, { title: 'Fullscreen' })) | ||
this.inputBtn.tooltip = atom.tooltips.add(this.inputBtn, { title: 'Insert Text' }) | ||
if (!this.shouldUseDock) { | ||
this.subscriptions.add(atom.tooltips.add(this.closeBtn, { title: 'Close' })) | ||
this.subscriptions.add(atom.tooltips.add(this.hideBtn, { title: 'Hide' })) | ||
this.subscriptions.add(this.maximizeBtn.tooltip = atom.tooltips.add(this.maximizeBtn, { title: 'Fullscreen' })) | ||
this.inputBtn.tooltip = atom.tooltips.add(this.inputBtn, { title: 'Insert Text' }) | ||
} | ||
|
||
this.prevHeight = atom.config.get('terminus.style.defaultPanelHeight') | ||
if (this.prevHeight.indexOf('%') > 0) { | ||
const percent = Math.abs(Math.min(parseFloat(this.prevHeight) / 100.0, 1)) | ||
const bottomHeight = $('atom-panel.bottom').children('.terminal-view').height() || 0 | ||
this.prevHeight = percent * ($('.item-views').height() + bottomHeight) | ||
} | ||
this.xterm.height(0) | ||
if (!this.shouldUseDock) { this.xterm.height(0) } | ||
|
||
this.setAnimationSpeed() | ||
this.subscriptions.add(atom.config.onDidChange('terminus.style.animationSpeed', this.setAnimationSpeed)) | ||
|
||
this.updateToolbarVisibility() | ||
this.subscriptions.add(atom.config.onDidChange('terminus.toggles.showToolbar', this.updateToolbarVisibility)) | ||
if (!this.shouldUseDock) { | ||
this.updateToolbarVisibility() | ||
this.subscriptions.add(atom.config.onDidChange('terminus.toggles.showToolbar', this.updateToolbarVisibility)) | ||
} | ||
|
||
const override = (event) => { | ||
if (event.originalEvent.dataTransfer.getData('terminus') === 'true') { return } | ||
|
@@ -112,8 +131,12 @@ class TerminusView extends View { | |
} | ||
|
||
attach () { | ||
if (this.panel) { return } | ||
this.panel = atom.workspace.addBottomPanel({ item: this, visible: false }) | ||
if (this.shouldUseDock) { | ||
atom.workspace.open(this) | ||
} else { | ||
if (this.panel) { return } | ||
this.panel = atom.workspace.addBottomPanel({ item: this, visible: false }) | ||
} | ||
} | ||
|
||
setAnimationSpeed () { | ||
|
@@ -199,10 +222,11 @@ class TerminusView extends View { | |
|
||
this.ptyProcess.on('terminus:title', title => { | ||
this.process = title | ||
this.emit('did-change-title') | ||
}) | ||
this.terminal.on('title', title => { | ||
this.title = title | ||
}) | ||
// this.terminal.on('title', title => { | ||
// this.title = title | ||
// }) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll be interested to check these title changes out. =) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good NewsI These changes you made into title actually fix #12 feel fee to submit them separately along with rename changes =) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually only fixed Linux side, Windows now doesnt even show any other name but xterm-256color |
||
|
||
this.terminal.once('open', () => { | ||
this.applyStyle() | ||
|
@@ -215,18 +239,24 @@ class TerminusView extends View { | |
}) | ||
} | ||
|
||
onDidDestroy (callback) { | ||
return this.emitter.on('did-destroy', callback) | ||
} | ||
|
||
destroy () { | ||
this.subscriptions.dispose() | ||
this.statusIcon.destroy() | ||
this.statusBar.removeTerminalView(this) | ||
this.detachResizeEvents() | ||
this.detachWindowEvents() | ||
|
||
if (this.panel.isVisible()) { | ||
this.hide() | ||
this.onTransitionEnd(() => this.panel.destroy()) | ||
} else { | ||
this.panel.destroy() | ||
if (!this.shouldUseDock) { | ||
if (this.panel.isVisible()) { | ||
this.hide() | ||
this.onTransitionEnd(() => this.panel.destroy()) | ||
} else { | ||
this.panel.destroy() | ||
} | ||
} | ||
|
||
if (this.statusIcon && this.statusIcon.parentNode) { | ||
|
@@ -239,6 +269,9 @@ class TerminusView extends View { | |
if (this.terminal) { | ||
this.terminal.destroy() | ||
} | ||
|
||
this.emit('did-destroy') | ||
this.emitter.dispose() | ||
} | ||
|
||
maximize () { | ||
|
@@ -269,6 +302,8 @@ class TerminusView extends View { | |
lastActiveElement = $(document.activeElement) | ||
} | ||
|
||
if (this.shouldUseDock) { return this.openInDock() } | ||
|
||
if (lastOpenedView && (lastOpenedView !== this)) { | ||
if (lastOpenedView.maximized) { | ||
this.subscriptions.remove(this.maximizeBtn.tooltip) | ||
|
@@ -306,7 +341,21 @@ class TerminusView extends View { | |
this.xterm.height(this.maximized ? this.maxHeight : this.prevHeight) | ||
} | ||
|
||
openInDock () { | ||
this.statusBar.setActiveTerminalView(this) | ||
this.statusIcon.activate() | ||
atom.workspace.open(this, { activatePane: true }).then(() => { | ||
if (!this.opened) { | ||
this.opened = true | ||
this.displayTerminal() | ||
this.xterm.height('100%') | ||
this.emit('terminus:terminal-open') | ||
} else this.focus() | ||
}) | ||
} | ||
|
||
hide () { | ||
if (this.shouldUseDock) return this.hideInDock() | ||
if (this.terminal) { | ||
this.terminal.blur() | ||
} | ||
|
@@ -328,7 +377,15 @@ class TerminusView extends View { | |
this.xterm.height(0) | ||
} | ||
|
||
hideInDock () { | ||
this.terminal && this.terminal.blur() | ||
this.statusIcon.deactivate() | ||
atom.workspace.hide(this) | ||
} | ||
|
||
toggle () { | ||
if (this.shouldUseDock) return this.toggleInDock() | ||
|
||
if (this.animating) { return } | ||
|
||
if (this.panel.isVisible()) { | ||
|
@@ -338,6 +395,10 @@ class TerminusView extends View { | |
} | ||
} | ||
|
||
toggleInDock () { | ||
if (isVisible(this)) { this.hide() } else { this.open() } | ||
} | ||
|
||
input (data) { | ||
if (!this.ptyProcess.childProcess) { return } | ||
|
||
|
@@ -614,6 +675,8 @@ class TerminusView extends View { | |
} | ||
|
||
resizeTerminalToView () { | ||
if (this.shouldUseDock) return this.resizeInDock() | ||
|
||
if (!this.panel.isVisible() && !this.tabView) { return } | ||
|
||
const { cols, rows } = this.getDimensions() | ||
|
@@ -625,6 +688,19 @@ class TerminusView extends View { | |
this.terminal.resize(cols, rows) | ||
} | ||
|
||
resizeInDock () { | ||
if (!isVisible(this)) return | ||
|
||
const { cols, rows } = this.getDimensions() | ||
if (cols > 0 && rows > 0) { | ||
if (this.terminal) { | ||
if (this.terminal.rows === rows && this.terminal.cols === cols) return | ||
this.resize(cols, rows) | ||
this.terminal.resize(cols, rows) | ||
} | ||
} | ||
} | ||
|
||
getDimensions () { | ||
const fakeRow = $('<div><span> </span></div>') | ||
|
||
|
@@ -657,8 +733,9 @@ class TerminusView extends View { | |
dialog.attach() | ||
} | ||
|
||
rename () { | ||
this.statusIcon.rename() | ||
didRename (title) { | ||
this.title = title | ||
this.emit('did-change-title') | ||
} | ||
|
||
toggleTabView () { | ||
|
@@ -682,6 +759,7 @@ class TerminusView extends View { | |
} | ||
|
||
getTitle () { | ||
if (this.shouldUseDock) { return this.getTerminalTitle() } | ||
return this.statusIcon.getName() || 'terminus' | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat, does this indeed also terminate the associated ptyProcess?