diff --git a/apps/remix-ide/src/app/panels/terminal.js b/apps/remix-ide/src/app/panels/terminal.js index bd474b41fb..a75f87187c 100644 --- a/apps/remix-ide/src/app/panels/terminal.js +++ b/apps/remix-ide/src/app/panels/terminal.js @@ -1,7 +1,10 @@ /* global Node, requestAnimationFrame */ + +import ReactDOM from 'react-dom' import { Plugin } from '@remixproject/engine' import * as packageJson from '../../../../../package.json' import * as remixBleach from '../../lib/remixBleach' +import { RemixUiTerminal } from '@remix-ui/terminal' var yo = require('yo-yo') var javascriptserialize = require('javascript-serialize') @@ -36,6 +39,8 @@ const profile = { class Terminal extends Plugin { constructor (opts, api) { super(profile) + this.element = document.createElement('div') + this.element.setAttribute('id', 'terminalView ') var self = this self.event = new EventManager() self.blockchain = opts.blockchain @@ -149,427 +154,435 @@ class Terminal extends Plugin { if (this._view.input) this._view.input.focus() } - render () { - var self = this - if (self._view.el) return self._view.el - self._view.journal = yo`
` - self._view.input = yo` - { this.focus() }} onpaste=${paste} onkeydown=${change}> - ` - self._view.input.setAttribute('spellcheck', 'false') - self._view.input.setAttribute('contenteditable', 'true') - self._view.input.setAttribute('id', 'terminalCliInput') - self._view.input.setAttribute('data-id', 'terminalCliInput') - - self._view.input.innerText = '\n' - self._view.cli = yo` -
- ${'>'} - ${self._view.input} -
- ` - - self._view.icon = yo` - ` - self._view.dragbar = yo` -
` - - self._view.pendingTxCount = yo`
0
` - self._view.inputSearch = yo` - ` - self._view.bar = yo` -
- ${self._view.dragbar} -
- ${self._view.icon} -
- -
- ${self._view.pendingTxCount} -
-
- - -
-
- - ${self._view.inputSearch} -
-
-
- ` - self._view.term = yo` -
- ${self._components.autoCompletePopup.render()} -
-
- ${self._view.journal} - ${self._view.cli} -
-
- ` - self._view.el = yo` -
- ${self._view.bar} - ${self._view.term} -
- ` - setInterval(async () => { - try { - self._view.pendingTxCount.innerHTML = await self.call('udapp', 'pendingTransactionsCount') - } catch (err) {} - }, 1000) - - function listenOnNetwork (ev) { - self.event.trigger('listenOnNetWork', [ev.currentTarget.checked]) - } - function paste (event) { - const selection = window.getSelection() - if (!selection.rangeCount) return false - event.preventDefault() - event.stopPropagation() - var clipboard = (event.clipboardData || window.clipboardData) - var text = clipboard.getData('text/plain') - text = text.replace(/[^\x20-\xFF]/gi, '') // remove non-UTF-8 characters - var temp = document.createElement('div') - temp.innerHTML = text - var textnode = document.createTextNode(temp.textContent) - selection.getRangeAt(0).insertNode(textnode) - selection.empty() - self.scroll2bottom() - placeCaretAtEnd(event.currentTarget) - } - function placeCaretAtEnd (el) { - el.focus() - var range = document.createRange() - range.selectNodeContents(el) - range.collapse(false) - var sel = window.getSelection() - sel.removeAllRanges() - sel.addRange(range) - } - function throttle (fn, wait) { - var time = Date.now() - return function debounce () { - if ((time + wait - Date.now()) < 0) { - fn.apply(this, arguments) - time = Date.now() - } - } - } - var css2 = csjs` - .anchor { - position : static; - border-top : 2px dotted blue; - height : 10px; - } - .overlay { - position : absolute; - width : 100%; - display : flex; - align-items : center; - justify-content : center; - bottom : 0; - right : 15px; - min-height : 20px; - } - .text { - z-index : 2; - color : black; - font-weight : bold; - pointer-events : none; - } - .background { - z-index : 1; - opacity : 0.8; - background-color : #a6aeba; - cursor : pointer; - } - .ul { - padding-left : 20px; - padding-bottom : 5px; - } - ` - var text = yo`
` - var background = yo`
` - var placeholder = yo`
${background}${text}
` - var inserted = false - - window.addEventListener('resize', function (event) { - self.event.trigger('resize', []) - self.event.trigger('resize', []) - }) - - function focusinput (event) { - if ( - event.altKey || - event.ctrlKey || - event.metaKey || - event.shiftKey || - event.key === 'Down' || - event.key === 'ArrowDown' || - event.key === 'Up' || - event.key === 'ArrowUp' || - event.key === 'Left' || - event.key === 'ArrowLeft' || - event.key === 'Right' || - event.key === 'ArrowRight' || - event.key === 'Esc' || - event.key === 'Escape' - ) return - - refocus() - } - - function refocus () { - self._view.input.focus() - reattach({ currentTarget: self._view.term }) - delete self.scroll2bottom - self.scroll2bottom() - } - function reattach (event) { - var el = event.currentTarget - var isBottomed = el.scrollHeight - el.scrollTop - el.clientHeight < 30 - if (isBottomed) { - if (inserted) { - text.innerText = '' - background.onclick = undefined - if (placeholder.parentElement) self._view.journal.removeChild(placeholder) - } - inserted = false - delete self.scroll2bottom - } else { - if (!inserted) self._view.journal.appendChild(placeholder) - inserted = true - check() - if (!placeholder.nextElementSibling) { - placeholder.style.display = 'none' - } else { - placeholder.style = '' - } - self.scroll2bottom = function () { - var next = placeholder.nextElementSibling - if (next) { - placeholder.style = '' - check() - var messages = 1 - while ((next = next.nextElementSibling)) messages += 1 - text.innerText = `${messages} new unread log entries` - } else { - placeholder.style.display = 'none' - } - } - } - } - function check () { - var pos1 = self._view.term.offsetHeight + self._view.term.scrollTop - (self._view.el.offsetHeight * 0.15) - var pos2 = placeholder.offsetTop - if ((pos1 - pos2) > 0) { - text.style.display = 'none' - background.style.position = 'relative' - background.style.opacity = 0.3 - background.style.right = 0 - background.style.borderBox = 'content-box' - background.style.padding = '2px' - background.style.height = (self._view.journal.offsetHeight - (placeholder.offsetTop + placeholder.offsetHeight)) + 'px' - background.onclick = undefined - background.style.cursor = 'default' - background.style.pointerEvents = 'none' - } else { - background.style = '' - text.style = '' - background.onclick = function (event) { - placeholder.scrollIntoView() - check() - } - } - } - function hover (event) { event.currentTarget.classList.toggle(css.hover) } - function minimize (event) { - event.preventDefault() - event.stopPropagation() - if (event.button === 0) { - var classList = self._view.icon.classList - classList.toggle('fa-angle-double-down') - classList.toggle('fa-angle-double-up') - self.event.trigger('resize', []) - } - } - var filtertimeout = null - function filter (event) { - if (filtertimeout) { - clearTimeout(filtertimeout) - } - filtertimeout = setTimeout(() => { - self.updateJournal({ type: 'search', value: self._view.inputSearch.value }) - self.scroll2bottom() - }, 500) - } - function clear (event) { - refocus() - self._view.journal.innerHTML = '' - } - // ----------------- resizeable ui --------------- - function mousedown (event) { - event.preventDefault() - if (event.which === 1) { - moveGhostbar(event) - document.body.appendChild(ghostbar) - document.addEventListener('mousemove', moveGhostbar) - document.addEventListener('mouseup', removeGhostbar) - document.addEventListener('keydown', cancelGhostbar) - } - } - function cancelGhostbar (event) { - if (event.keyCode === 27) { - document.body.removeChild(ghostbar) - document.removeEventListener('mousemove', moveGhostbar) - document.removeEventListener('mouseup', removeGhostbar) - document.removeEventListener('keydown', cancelGhostbar) - } - } - function moveGhostbar (event) { // @NOTE HORIZONTAL ghostbar - ghostbar.style.top = self._api.getPosition(event) + 'px' - } - function removeGhostbar (event) { - if (self._view.icon.classList.contains('fa-angle-double-up')) { - self._view.icon.classList.toggle('fa-angle-double-down') - self._view.icon.classList.toggle('fa-angle-double-up') - } - document.body.removeChild(ghostbar) - document.removeEventListener('mousemove', moveGhostbar) - document.removeEventListener('mouseup', removeGhostbar) - document.removeEventListener('keydown', cancelGhostbar) - self.event.trigger('resize', [self._api.getPosition(event)]) - } + // render () { + // var self = this + // if (self._view.el) return self._view.el + // self._view.journal = yo`
` + // self._view.input = yo` + // { this.focus() }} onpaste=${paste} onkeydown=${change}> + // ` + // self._view.input.setAttribute('spellcheck', 'false') + // self._view.input.setAttribute('contenteditable', 'true') + // self._view.input.setAttribute('id', 'terminalCliInput') + // self._view.input.setAttribute('data-id', 'terminalCliInput') + + // self._view.input.innerText = '\n' + // self._view.cli = yo` + //
+ // ${'>'} + // ${self._view.input} + //
+ // ` + + // self._view.icon = yo` + // ` + // self._view.dragbar = yo` + //
` + + // self._view.pendingTxCount = yo`
0
` + // self._view.inputSearch = yo` + // ` + // self._view.bar = yo` + //
+ // ${self._view.dragbar} + //
+ // ${self._view.icon} + //
+ // + //
+ // ${self._view.pendingTxCount} + //
+ //
+ // + // + //
+ //
+ // + // ${self._view.inputSearch} + //
+ //
+ //
+ // ` + // self._view.term = yo` + //
+ // ${self._components.autoCompletePopup.render()} + //
+ //
+ // ${self._view.journal} + // ${self._view.cli} + //
+ //
+ // ` + // self._view.el = yo` + //
+ // ${self._view.bar} + // ${self._view.term} + //
+ // ` + // setInterval(async () => { + // try { + // self._view.pendingTxCount.innerHTML = await self.call('udapp', 'pendingTransactionsCount') + // } catch (err) {} + // }, 1000) + + // function listenOnNetwork (ev) { + // self.event.trigger('listenOnNetWork', [ev.currentTarget.checked]) + // } + // function paste (event) { + // const selection = window.getSelection() + // if (!selection.rangeCount) return false + // event.preventDefault() + // event.stopPropagation() + // var clipboard = (event.clipboardData || window.clipboardData) + // var text = clipboard.getData('text/plain') + // text = text.replace(/[^\x20-\xFF]/gi, '') // remove non-UTF-8 characters + // var temp = document.createElement('div') + // temp.innerHTML = text + // var textnode = document.createTextNode(temp.textContent) + // selection.getRangeAt(0).insertNode(textnode) + // selection.empty() + // self.scroll2bottom() + // placeCaretAtEnd(event.currentTarget) + // } + // function placeCaretAtEnd (el) { + // el.focus() + // var range = document.createRange() + // range.selectNodeContents(el) + // range.collapse(false) + // var sel = window.getSelection() + // sel.removeAllRanges() + // sel.addRange(range) + // } + // function throttle (fn, wait) { + // var time = Date.now() + // return function debounce () { + // if ((time + wait - Date.now()) < 0) { + // fn.apply(this, arguments) + // time = Date.now() + // } + // } + // } + // var css2 = csjs` + // .anchor { + // position : static; + // border-top : 2px dotted blue; + // height : 10px; + // } + // .overlay { + // position : absolute; + // width : 100%; + // display : flex; + // align-items : center; + // justify-content : center; + // bottom : 0; + // right : 15px; + // min-height : 20px; + // } + // .text { + // z-index : 2; + // color : black; + // font-weight : bold; + // pointer-events : none; + // } + // .background { + // z-index : 1; + // opacity : 0.8; + // background-color : #a6aeba; + // cursor : pointer; + // } + // .ul { + // padding-left : 20px; + // padding-bottom : 5px; + // } + // ` + // var text = yo`
` + // var background = yo`
` + // var placeholder = yo`
${background}${text}
` + // var inserted = false + + // window.addEventListener('resize', function (event) { + // self.event.trigger('resize', []) + // self.event.trigger('resize', []) + // }) + + // function focusinput (event) { + // if ( + // event.altKey || + // event.ctrlKey || + // event.metaKey || + // event.shiftKey || + // event.key === 'Down' || + // event.key === 'ArrowDown' || + // event.key === 'Up' || + // event.key === 'ArrowUp' || + // event.key === 'Left' || + // event.key === 'ArrowLeft' || + // event.key === 'Right' || + // event.key === 'ArrowRight' || + // event.key === 'Esc' || + // event.key === 'Escape' + // ) return + + // refocus() + // } + + // function refocus () { + // self._view.input.focus() + // reattach({ currentTarget: self._view.term }) + // delete self.scroll2bottom + // self.scroll2bottom() + // } + // function reattach (event) { + // var el = event.currentTarget + // var isBottomed = el.scrollHeight - el.scrollTop - el.clientHeight < 30 + // if (isBottomed) { + // if (inserted) { + // text.innerText = '' + // background.onclick = undefined + // if (placeholder.parentElement) self._view.journal.removeChild(placeholder) + // } + // inserted = false + // delete self.scroll2bottom + // } else { + // if (!inserted) self._view.journal.appendChild(placeholder) + // inserted = true + // check() + // if (!placeholder.nextElementSibling) { + // placeholder.style.display = 'none' + // } else { + // placeholder.style = '' + // } + // self.scroll2bottom = function () { + // var next = placeholder.nextElementSibling + // if (next) { + // placeholder.style = '' + // check() + // var messages = 1 + // while ((next = next.nextElementSibling)) messages += 1 + // text.innerText = `${messages} new unread log entries` + // } else { + // placeholder.style.display = 'none' + // } + // } + // } + // } + // function check () { + // var pos1 = self._view.term.offsetHeight + self._view.term.scrollTop - (self._view.el.offsetHeight * 0.15) + // var pos2 = placeholder.offsetTop + // if ((pos1 - pos2) > 0) { + // text.style.display = 'none' + // background.style.position = 'relative' + // background.style.opacity = 0.3 + // background.style.right = 0 + // background.style.borderBox = 'content-box' + // background.style.padding = '2px' + // background.style.height = (self._view.journal.offsetHeight - (placeholder.offsetTop + placeholder.offsetHeight)) + 'px' + // background.onclick = undefined + // background.style.cursor = 'default' + // background.style.pointerEvents = 'none' + // } else { + // background.style = '' + // text.style = '' + // background.onclick = function (event) { + // placeholder.scrollIntoView() + // check() + // } + // } + // } + // function hover (event) { event.currentTarget.classList.toggle(css.hover) } + // function minimize (event) { + // event.preventDefault() + // event.stopPropagation() + // if (event.button === 0) { + // var classList = self._view.icon.classList + // classList.toggle('fa-angle-double-down') + // classList.toggle('fa-angle-double-up') + // self.event.trigger('resize', []) + // } + // } + // var filtertimeout = null + // function filter (event) { + // if (filtertimeout) { + // clearTimeout(filtertimeout) + // } + // filtertimeout = setTimeout(() => { + // self.updateJournal({ type: 'search', value: self._view.inputSearch.value }) + // self.scroll2bottom() + // }, 500) + // } + // function clear (event) { + // refocus() + // self._view.journal.innerHTML = '' + // } + // // ----------------- resizeable ui --------------- + // function mousedown (event) { + // event.preventDefault() + // if (event.which === 1) { + // moveGhostbar(event) + // document.body.appendChild(ghostbar) + // document.addEventListener('mousemove', moveGhostbar) + // document.addEventListener('mouseup', removeGhostbar) + // document.addEventListener('keydown', cancelGhostbar) + // } + // } + // function cancelGhostbar (event) { + // if (event.keyCode === 27) { + // document.body.removeChild(ghostbar) + // document.removeEventListener('mousemove', moveGhostbar) + // document.removeEventListener('mouseup', removeGhostbar) + // document.removeEventListener('keydown', cancelGhostbar) + // } + // } + // function moveGhostbar (event) { // @NOTE HORIZONTAL ghostbar + // ghostbar.style.top = self._api.getPosition(event) + 'px' + // } + // function removeGhostbar (event) { + // if (self._view.icon.classList.contains('fa-angle-double-up')) { + // self._view.icon.classList.toggle('fa-angle-double-down') + // self._view.icon.classList.toggle('fa-angle-double-up') + // } + // document.body.removeChild(ghostbar) + // document.removeEventListener('mousemove', moveGhostbar) + // document.removeEventListener('mouseup', removeGhostbar) + // document.removeEventListener('keydown', cancelGhostbar) + // self.event.trigger('resize', [self._api.getPosition(event)]) + // } + + // self._cmdHistory = [] + // self._cmdIndex = -1 + // self._cmdTemp = '' + + // var intro = yo` + //
- Welcome to Remix ${packageJson.version} -

+ //
You can use this terminal to:
+ // + //
The following libraries are accessible:
+ // + //
+ // ` + + // self._shell('remix.help()', self.commands, () => {}) + // self.commands.html(intro) + + // self._components.txLogger = new TxLogger(this, self.blockchain) + // self._components.txLogger.event.register('debuggingRequested', async (hash) => { + // // TODO should probably be in the run module + // if (!await self._opts.appManager.isActive('debugger')) await self._opts.appManager.activatePlugin('debugger') + // this.call('menuicons', 'select', 'debugger') + // this.call('debugger', 'debug', hash) + // }) + + // return self._view.el + + // function wrapScript (script) { + // const isKnownScript = ['remix.', 'git'].some(prefix => script.trim().startsWith(prefix)) + // if (isKnownScript) return script + // return ` + // try { + // const ret = ${script}; + // if (ret instanceof Promise) { + // ret.then((result) => { console.log(result) }).catch((error) => { console.log(error) }) + // } else { + // console.log(ret) + // } + // } catch (e) { + // console.log(e.message) + // } + // ` + // } + // function change (event) { + // if (self._components.autoCompletePopup.handleAutoComplete( + // event, + // self._view.input.innerText)) return + // if (self._view.input.innerText.length === 0) self._view.input.innerText += '\n' + // if (event.which === 13) { + // if (event.ctrlKey) { // + // self._view.input.innerText += '\n' + // self.putCursor2End(self._view.input) + // self.scroll2bottom() + // self._components.autoCompletePopup.removeAutoComplete() + // } else { // + // self._cmdIndex = -1 + // self._cmdTemp = '' + // event.preventDefault() + // var script = self._view.input.innerText.trim() + // self._view.input.innerText = '\n' + // if (script.length) { + // self._cmdHistory.unshift(script) + // self.commands.script(wrapScript(script)) + // } + // self._components.autoCompletePopup.removeAutoComplete() + // } + // } else if (event.which === 38) { // + // var len = self._cmdHistory.length + // if (len === 0) return event.preventDefault() + // if (self._cmdHistory.length - 1 > self._cmdIndex) { + // self._cmdIndex++ + // } + // self._view.input.innerText = self._cmdHistory[self._cmdIndex] + // self.putCursor2End(self._view.input) + // self.scroll2bottom() + // } else if (event.which === 40) { // + // if (self._cmdIndex > -1) { + // self._cmdIndex-- + // } + // self._view.input.innerText = self._cmdIndex >= 0 ? self._cmdHistory[self._cmdIndex] : self._cmdTemp + // self.putCursor2End(self._view.input) + // self.scroll2bottom() + // } else { + // self._cmdTemp = self._view.input.innerText + // } + // } + // } - self._cmdHistory = [] - self._cmdIndex = -1 - self._cmdTemp = '' - - var intro = yo` -
- Welcome to Remix ${packageJson.version} -

-
You can use this terminal to:
-
    -
  • Check transactions details and start debugging.
  • -
  • Execute JavaScript scripts: -
    - - Input a script directly in the command line interface -
    - - Select a Javascript file in the file explorer and then run \`remix.execute()\` or \`remix.exeCurrent()\` in the command line interface -
    - - Right click on a JavaScript file in the file explorer and then click \`Run\` -
  • -
-
The following libraries are accessible:
- -
- ` - - self._shell('remix.help()', self.commands, () => {}) - self.commands.html(intro) - - self._components.txLogger = new TxLogger(this, self.blockchain) - self._components.txLogger.event.register('debuggingRequested', async (hash) => { - // TODO should probably be in the run module - if (!await self._opts.appManager.isActive('debugger')) await self._opts.appManager.activatePlugin('debugger') - this.call('menuicons', 'select', 'debugger') - this.call('debugger', 'debug', hash) - }) + render () { + return this.element + } - return self._view.el - - function wrapScript (script) { - const isKnownScript = ['remix.', 'git'].some(prefix => script.trim().startsWith(prefix)) - if (isKnownScript) return script - return ` - try { - const ret = ${script}; - if (ret instanceof Promise) { - ret.then((result) => { console.log(result) }).catch((error) => { console.log(error) }) - } else { - console.log(ret) - } - } catch (e) { - console.log(e.message) - } - ` - } - function change (event) { - if (self._components.autoCompletePopup.handleAutoComplete( - event, - self._view.input.innerText)) return - if (self._view.input.innerText.length === 0) self._view.input.innerText += '\n' - if (event.which === 13) { - if (event.ctrlKey) { // - self._view.input.innerText += '\n' - self.putCursor2End(self._view.input) - self.scroll2bottom() - self._components.autoCompletePopup.removeAutoComplete() - } else { // - self._cmdIndex = -1 - self._cmdTemp = '' - event.preventDefault() - var script = self._view.input.innerText.trim() - self._view.input.innerText = '\n' - if (script.length) { - self._cmdHistory.unshift(script) - self.commands.script(wrapScript(script)) - } - self._components.autoCompletePopup.removeAutoComplete() - } - } else if (event.which === 38) { // - var len = self._cmdHistory.length - if (len === 0) return event.preventDefault() - if (self._cmdHistory.length - 1 > self._cmdIndex) { - self._cmdIndex++ - } - self._view.input.innerText = self._cmdHistory[self._cmdIndex] - self.putCursor2End(self._view.input) - self.scroll2bottom() - } else if (event.which === 40) { // - if (self._cmdIndex > -1) { - self._cmdIndex-- - } - self._view.input.innerText = self._cmdIndex >= 0 ? self._cmdHistory[self._cmdIndex] : self._cmdTemp - self.putCursor2End(self._view.input) - self.scroll2bottom() - } else { - self._cmdTemp = self._view.input.innerText - } - } + renderComponent () { + ReactDOM.render(, this.element) } putCursor2End (editable) { diff --git a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx index 337bb2e1bb..f8418db3f2 100644 --- a/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx +++ b/libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx @@ -8,9 +8,9 @@ export interface RemixUiTerminalProps {} export const RemixUiTerminal = (props: RemixUiTerminalProps) => { return (
-

Welcome to remix-ui-terminal!

+ Welcome to remix-ui-terminal
) } -export default RemixUiTerminal; +export default RemixUiTerminal