Repository navigation
Expand file tree
/
Copy pathTerminalInstance.js
More file actions
1 lines (1 loc) · 7.67 KB
/
Copy pathTerminalInstance.js
File metadata and controls
1 lines (1 loc) · 7.67 KB
1
define(function(require,exports,module){const xtermModule=require("thirdparty/xterm/xterm"),FitAddonModule=require("thirdparty/xterm/addon-fit"),WebLinksAddonModule=require("thirdparty/xterm/addon-web-links"),SearchAddonModule=require("thirdparty/xterm/addon-search"),WebglAddonModule=require("thirdparty/xterm/addon-webgl"),Terminal=xtermModule.Terminal,FitAddon=FitAddonModule.FitAddon,WebLinksAddon=WebLinksAddonModule.WebLinksAddon,SearchAddon=SearchAddonModule.SearchAddon,WebglAddon=WebglAddonModule.WebglAddon;let _nextId=0;function _openLink(uri){/^https?:\/\//i.test(uri)&&Phoenix.app.openURLInDefaultBrowser(uri).catch(function(err){console.error("Terminal: could not open link:",uri,err)})}function _getThemeFromCSS(baseEl){const panelEl=baseEl||document.querySelector(".terminal-panel-container")||document.documentElement,style=getComputedStyle(panelEl);function v(name){return style.getPropertyValue(name).trim()||void 0}return{background:v("--terminal-background"),foreground:v("--terminal-foreground"),cursor:v("--terminal-cursor"),cursorAccent:v("--terminal-background"),selectionBackground:v("--terminal-selection"),selectionForeground:void 0,overviewRulerBorder:"transparent",black:v("--terminal-ansi-black"),red:v("--terminal-ansi-red"),green:v("--terminal-ansi-green"),yellow:v("--terminal-ansi-yellow"),blue:v("--terminal-ansi-blue"),magenta:v("--terminal-ansi-magenta"),cyan:v("--terminal-ansi-cyan"),white:v("--terminal-ansi-white"),brightBlack:v("--terminal-ansi-bright-black"),brightRed:v("--terminal-ansi-bright-red"),brightGreen:v("--terminal-ansi-bright-green"),brightYellow:v("--terminal-ansi-bright-yellow"),brightBlue:v("--terminal-ansi-bright-blue"),brightMagenta:v("--terminal-ansi-bright-magenta"),brightCyan:v("--terminal-ansi-bright-cyan"),brightWhite:v("--terminal-ansi-bright-white")}}function TerminalInstance(nodeConnector,shellProfile,cwd){this.id="term_"+ ++_nextId,this.nodeConnector=nodeConnector,this.shellProfile=shellProfile,this.cwd=cwd,this.title=shellProfile.name,this.pid=null,this.isAlive=!1,this.terminal=null,this.fitAddon=null,this.searchAddon=null,this.$container=null,this._resizeTimeout=null,this._disposed=!1,this._processExited=!1,this._webglAddon=null,this._lastDpr=null,this._firstDataResolve=null,this.firstDataReceived=new Promise(function(resolve){this._firstDataResolve=resolve}.bind(this)),this._onTerminalData=this._onTerminalData.bind(this),this._onTerminalExit=this._onTerminalExit.bind(this)}TerminalInstance.prototype.create=function($parentContainer){this.$container=$('<div class="terminal-instance-container" data-terminal-id="'+this.id+'"></div>'),$parentContainer.append(this.$container),this.terminal=new Terminal({theme:_getThemeFromCSS(this.$container[0]),fontFamily:"'Menlo', 'DejaVu Sans Mono', 'Consolas', 'Lucida Console', monospace",fontSize:13,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:1e4,scrollbar:{width:12},allowProposedApi:!0,linkHandler:{activate:function(_event,uri){_openLink(uri)}}}),this.fitAddon=new FitAddon,this.searchAddon=new SearchAddon,this.terminal.loadAddon(this.fitAddon),this.terminal.loadAddon(new WebLinksAddon(function(_event,uri){_openLink(uri)})),this.terminal.loadAddon(this.searchAddon),this.terminal.open(this.$container[0]),this._loadWebGLAddon(),this._fit(),this.terminal.attachCustomKeyEventHandler(this._customKeyHandler.bind(this)),this.terminal.onData(data=>{this.isAlive&&this.nodeConnector.execPeer("writeTerminal",{id:this.id,data:data}).catch(err=>{console.error("Terminal: write error:",err)})}),this.terminal.onResize(({cols:cols,rows:rows})=>{this.isAlive&&this.nodeConnector.execPeer("resizeTerminal",{id:this.id,cols:cols,rows:rows}).catch(err=>{console.error("Terminal: resize error:",err)})}),this.terminal.onTitleChange(newTitle=>{newTitle&&(this.title=newTitle,this.onTitleChanged&&this.onTitleChanged(this.id,newTitle))}),this.nodeConnector.on("terminalData",this._onTerminalData),this.nodeConnector.on("terminalExit",this._onTerminalExit)},TerminalInstance.prototype.spawn=async function(env,options){const dims=this.fitAddon.proposeDimensions(),connectorSessionId=options&&options.connectorSessionId;try{const result=await this.nodeConnector.execPeer("createTerminal",{id:this.id,shell:this.shellProfile.path,args:this.shellProfile.args||[],cwd:this.cwd,cols:dims?dims.cols:80,rows:dims?dims.rows:24,env:env||void 0,connectorSessionId:connectorSessionId||void 0});return this.pid=result.pid,this.isAlive=!this._processExited&&!this._disposed,!0}catch(err){return console.error("Terminal: Failed to spawn PTY:",err),this.terminal.write("\r\n[31mFailed to start terminal: "+err.message+"[0m\r\n"),!1}},TerminalInstance.prototype._onTerminalData=function(_event,eventData){eventData.id===this.id&&this.terminal&&(this.terminal.write(eventData.data),this._firstDataResolve&&(this._firstDataResolve(),this._firstDataResolve=null))},TerminalInstance.prototype._onTerminalExit=function(_event,eventData){eventData.id===this.id&&(this._processExited=!0,this.isAlive=!1,this.terminal&&this.terminal.write("\r\n[90m[Process exited with code "+eventData.exitCode+"][0m\r\n"),this.onProcessExit&&this.onProcessExit(this.id,eventData.exitCode))},TerminalInstance.prototype._customKeyHandler=function(event){if("keydown"!==event.type)return!0;const ctrlOrMeta=event.ctrlKey||event.metaKey;return(!event.shiftKey||"Escape"!==event.key)&&!(ctrlOrMeta&&!event.shiftKey&&"c"===event.key.toLowerCase()&&this.terminal.hasSelection())},TerminalInstance.prototype._loadWebGLAddon=function(){try{this._webglAddon=new WebglAddon,this.terminal.loadAddon(this._webglAddon),this._lastDpr=window.devicePixelRatio}catch(e){console.warn("Terminal: WebglAddon failed to load, using default renderer:",e),this._webglAddon=null}},TerminalInstance.prototype._fit=function(){if(!this.fitAddon||!this.$container||!this.$container.is(":visible"))return;const currentDpr=window.devicePixelRatio;null!==this._lastDpr&&this._lastDpr!==currentDpr&&(this._lastDpr=currentDpr,this.terminal.clearTextureAtlas());try{if(this.terminal&&this.isAlive){const proposed=this.fitAddon.proposeDimensions(),dimensionsChanged=proposed&&(proposed.cols!==this.terminal.cols||proposed.rows!==this.terminal.rows);if(dimensionsChanged){const buf=this.terminal.buffer.active;let promptStart=buf.cursorY;for(;promptStart>0;){const line=buf.getLine(buf.baseY+promptStart);if(!line||!line.isWrapped)break;promptStart--}return void this.terminal.write("["+(promptStart+1)+";1H[J",()=>{try{this.fitAddon.fit()}catch(e){}})}}this.fitAddon.fit()}catch(e){}},TerminalInstance.prototype.handleResize=function(){clearTimeout(this._resizeTimeout),this._resizeTimeout=setTimeout(()=>{this._fit()},300)},TerminalInstance.prototype.show=function(){this.$container&&(this.$container.addClass("active"),this._fit(),this.terminal.focus())},TerminalInstance.prototype.hide=function(){this.$container&&this.$container.removeClass("active")},TerminalInstance.prototype.focus=function(){this.terminal&&this.terminal.focus()},TerminalInstance.prototype.clear=function(){this.terminal&&this.terminal.clear()},TerminalInstance.prototype.updateTheme=function(){this.terminal&&(this.terminal.options.theme=_getThemeFromCSS(this.$container?this.$container[0]:null))},TerminalInstance.prototype.dispose=function(){this._disposed||(this._disposed=!0,this.nodeConnector.off("terminalData",this._onTerminalData),this.nodeConnector.off("terminalExit",this._onTerminalExit),this.isAlive&&(this.nodeConnector.execPeer("killTerminal",{id:this.id}).catch(err=>{console.error("Terminal: kill error:",err)}),this.isAlive=!1),clearTimeout(this._resizeTimeout),this._webglAddon&&(this._webglAddon.dispose(),this._webglAddon=null),this.terminal&&(this.terminal.dispose(),this.terminal=null),this.$container&&(this.$container.remove(),this.$container=null))},module.exports=TerminalInstance});