diff --git a/7.png b/7.png new file mode 100644 index 00000000..b615872a Binary files /dev/null and b/7.png differ diff --git a/README.md b/README.md index 43f9bc61..93673db2 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ + 重命名文件/目录:`Ctrl + 右键文件/目录` + 切换文档预览显示:`Alt + V` 或点击状态栏 `切换预览` 按钮 + 切换编辑器自动换行:`Alt + W` 或点击状态栏 `切换换行` 按钮 ++ 切换内置终端展示:`Alt + O` 或点击状态栏 `切换终端` 按钮 + 将外链或 BASE64 图片转换为本地图片:`Ctrl + Shift + 单击图片` + 默认文件存储在 `./data` 目录下,添加更多仓库请编辑 `./config.json` 文件 + 默认快捷键参考 [vscode](https://code.visualstudio.com/) @@ -88,6 +89,7 @@ + katex 公式解析 [markdown-it-katex](https://github.com/waylonflinn/markdown-it-katex) + 元素属性书写 [markdown-it-attrs](https://github.com/arve0/markdown-it-attrs) + 表格解析增强,支持表格标题多行文本,列表等特性 [markdown-it-multimd-table](https://github.com/RedBug312/markdown-it-multimd-table) ++ 内置终端 [XTERM.JS](https://xtermjs.org/) [node-pty](https://github.com/Microsoft/node-pty) ## 开发 + 后端: `cd backend; node main.js` @@ -124,6 +126,7 @@ + [x] 支持多根目录 + [x] 状态栏 + [x] toc 生成 ++ [x] 内置终端 + [ ] 代码块渲染增加行号 + [ ] 信息流,定时任务 + [ ] 标签支持 @@ -141,3 +144,4 @@ ![截图](./4.png) ![截图](./5.gif) ![截图](./6.png) +![截图](./7.png) diff --git a/backend/main.js b/backend/main.js index c227db49..34563cef 100644 --- a/backend/main.js +++ b/backend/main.js @@ -4,6 +4,7 @@ const bodyParser = require('koa-body') const static = require('koa-static') const mime = require('mime') const request = require('request') +const pty = require('node-pty') const file = require('./file') const dataRepository = require('./repository') @@ -171,6 +172,23 @@ app.use(async (ctx, next) => await wrapper(ctx, next, repository)) app.use(async (ctx, next) => await wrapper(ctx, next, proxy)) const port = 3000 -app.listen(port) + +const server = require('http').createServer(app.callback()) +const io = require('socket.io')(server, {path: '/ws'}) + +io.on('connection', socket => { + const ptyProcess = pty.spawn('bash', ['--login'], { + name: 'xterm-color', + cols: 80, + rows: 24, + cwd: path.join(__dirname, '../'), + env: process.env + }) + ptyProcess.on('data', data => socket.emit('output', data)) + socket.on('input', data => ptyProcess.write(data)) + socket.on('resize', size => ptyProcess.resize(size[0], size[1])) +}) + +server.listen(port) console.log(`访问地址:http://localhost:${port}`) diff --git a/backend/package.json b/backend/package.json index 0baa70e5..8162baeb 100644 --- a/backend/package.json +++ b/backend/package.json @@ -7,8 +7,10 @@ "mime": "^2.2.0", "natural-orderby": "^1.0.2", "node-plantuml": "^0.6.2", + "node-pty": "^0.8.1", "opn": "^5.3.0", "request": "^2.88.0", - "safe-buffer": "^5.1.2" + "safe-buffer": "^5.1.2", + "socket.io": "^2.2.0" } } diff --git a/backend/yarn.lock b/backend/yarn.lock index 2ca2a585..dd53b0c1 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -9,6 +9,17 @@ accepts@^1.2.2: mime-types "~2.1.16" negotiator "0.6.1" +accepts@~1.3.4: + version "1.3.5" + resolved "http://registry.npm.taobao.org/accepts/download/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +after@0.8.2: + version "0.8.2" + resolved "http://registry.npm.taobao.org/after/download/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + ajv@^5.3.0: version "5.5.2" resolved "http://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" @@ -22,6 +33,10 @@ any-promise@^1.0.0, any-promise@^1.1.0: version "1.3.0" resolved "http://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "http://registry.npm.taobao.org/arraybuffer.slice/download/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + asn1@~0.2.3: version "0.2.4" resolved "http://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -32,6 +47,10 @@ assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" resolved "http://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" +async-limiter@~1.0.0: + version "1.0.0" + resolved "http://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + asynckit@^0.4.0: version "0.4.0" resolved "http://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -44,16 +63,42 @@ aws4@^1.8.0: version "1.8.0" resolved "http://registry.npm.taobao.org/aws4/download/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" +backo2@1.0.2: + version "1.0.2" + resolved "http://registry.npm.taobao.org/backo2/download/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "http://registry.npm.taobao.org/base64-arraybuffer/download/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + +base64id@1.0.0: + version "1.0.0" + resolved "http://registry.npm.taobao.org/base64id/download/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + bcrypt-pbkdf@^1.0.0: version "1.0.2" resolved "http://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" dependencies: tweetnacl "^0.14.3" +better-assert@~1.0.0: + version "1.0.2" + resolved "http://registry.npm.taobao.org/better-assert/download/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + +blob@0.0.5: + version "0.0.5" + resolved "http://registry.npm.taobao.org/blob/download/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + bytes@3.0.0: version "3.0.0" resolved "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" +callsite@1.0.0: + version "1.0.0" + resolved "http://registry.npm.taobao.org/callsite/download/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + caseless@~0.12.0: version "0.12.0" resolved "http://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -81,6 +126,18 @@ commander@^2.8.1: version "2.16.0" resolved "http://registry.npm.taobao.org/commander/download/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" +component-bind@1.0.0: + version "1.0.0" + resolved "http://registry.npm.taobao.org/component-bind/download/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + +component-emitter@1.2.1: + version "1.2.1" + resolved "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +component-inherit@0.0.3: + version "0.0.3" + resolved "http://registry.npm.taobao.org/component-inherit/download/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + content-disposition@~0.5.0: version "0.5.2" resolved "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -89,6 +146,10 @@ content-type@^1.0.0: version "1.0.4" resolved "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" +cookie@0.3.1: + version "0.3.1" + resolved "http://registry.npm.taobao.org/cookie/download/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + cookies@~0.7.0: version "0.7.1" resolved "http://registry.npm.taobao.org/cookies/download/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" @@ -106,7 +167,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@*: +debug@*, debug@~3.1.0: version "3.1.0" resolved "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -118,6 +179,12 @@ debug@^2.6.3, debug@^2.6.8: dependencies: ms "2.0.0" +debug@~4.1.0: + version "4.1.1" + resolved "http://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + dependencies: + ms "^2.1.1" + deep-equal@~1.0.1: version "1.0.1" resolved "http://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -153,6 +220,43 @@ ee-first@1.1.1: version "1.1.1" resolved "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" +engine.io-client@~3.3.1: + version "3.3.2" + resolved "http://registry.npm.taobao.org/engine.io-client/download/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "http://registry.npm.taobao.org/engine.io-parser/download/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.3.1: + version "3.3.2" + resolved "http://registry.npm.taobao.org/engine.io/download/engine.io-3.3.2.tgz#18cbc8b6f36e9461c5c0f81df2b830de16058a59" + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~6.1.0" + error-inject@~1.0.0: version "1.0.0" resolved "http://registry.npm.taobao.org/error-inject/download/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" @@ -230,6 +334,16 @@ har-validator@~5.1.0: ajv "^5.3.0" har-schema "^2.0.0" +has-binary2@~1.0.2: + version "1.0.3" + resolved "http://registry.npm.taobao.org/has-binary2/download/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "http://registry.npm.taobao.org/has-cors/download/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + http-assert@^1.1.0: version "1.3.0" resolved "http://registry.npm.taobao.org/http-assert/download/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" @@ -258,6 +372,10 @@ iconv-lite@0.4.19: version "0.4.19" resolved "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +indexof@0.0.1: + version "0.0.1" + resolved "http://registry.npm.taobao.org/indexof/download/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + inflation@^2.0.0: version "2.0.0" resolved "http://registry.npm.taobao.org/inflation/download/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" @@ -278,6 +396,10 @@ is-wsl@^1.1.0: version "1.1.0" resolved "http://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" +isarray@2.0.1: + version "2.0.1" + resolved "http://registry.npm.taobao.org/isarray/download/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + isstream@~0.1.2: version "0.1.2" resolved "http://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -402,6 +524,10 @@ mime-db@~1.35.0: version "1.35.0" resolved "http://registry.npm.taobao.org/mime-db/download/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" +mime-db@~1.37.0: + version "1.37.0" + resolved "http://registry.npm.taobao.org/mime-db/download/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + mime-types@^2.0.7, mime-types@~2.1.15, mime-types@~2.1.16: version "2.1.17" resolved "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" @@ -414,6 +540,12 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "~1.35.0" +mime-types@~2.1.18: + version "2.1.21" + resolved "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + dependencies: + mime-db "~1.37.0" + mime@^2.2.0: version "2.2.0" resolved "http://registry.npm.taobao.org/mime/download/mime-2.2.0.tgz#161e541965551d3b549fa1114391e3a3d55b923b" @@ -422,6 +554,10 @@ ms@2.0.0: version "2.0.0" resolved "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +ms@^2.1.1: + version "2.1.1" + resolved "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + mz@^2.6.0: version "2.7.0" resolved "http://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -430,6 +566,10 @@ mz@^2.6.0: object-assign "^4.0.1" thenify-all "^1.0.0" +nan@2.12.1: + version "2.12.1" + resolved "http://registry.npm.taobao.org/nan/download/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + natural-orderby@^1.0.2: version "1.0.2" resolved "http://registry.npm.taobao.org/natural-orderby/download/natural-orderby-1.0.2.tgz#287a4778217fbf6af0d704129d55ae90450f7a88" @@ -459,6 +599,12 @@ node-plantuml@^0.6.2: node-nailgun-server "^0.1.3" plantuml-encoder "^1.2.5" +node-pty@^0.8.1: + version "0.8.1" + resolved "http://registry.npm.taobao.org/node-pty/download/node-pty-0.8.1.tgz#94b457bec013e7a09b8d9141f63b0787fa25c23f" + dependencies: + nan "2.12.1" + oauth-sign@~0.9.0: version "0.9.0" resolved "http://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -467,6 +613,10 @@ object-assign@^4.0.1: version "4.1.1" resolved "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" +object-component@0.0.3: + version "0.0.3" + resolved "http://registry.npm.taobao.org/object-component/download/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + on-finished@^2.1.0: version "2.3.0" resolved "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -487,6 +637,18 @@ pako@1.0.3: version "1.0.3" resolved "http://registry.npm.taobao.org/pako/download/pako-1.0.3.tgz#5f515b0c6722e1982920ae8005eacb0b7ca73ccf" +parseqs@0.0.5: + version "0.0.5" + resolved "http://registry.npm.taobao.org/parseqs/download/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "http://registry.npm.taobao.org/parseuri/download/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + dependencies: + better-assert "~1.0.0" + parseurl@^1.3.0: version "1.3.2" resolved "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" @@ -575,6 +737,48 @@ setprototypeof@1.0.3: version "1.0.3" resolved "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" +socket.io-adapter@~1.1.0: + version "1.1.1" + resolved "http://registry.npm.taobao.org/socket.io-adapter/download/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" + +socket.io-client@2.2.0: + version "2.2.0" + resolved "http://registry.npm.taobao.org/socket.io-client/download/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.3.1" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "http://registry.npm.taobao.org/socket.io-parser/download/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@^2.2.0: + version "2.2.0" + resolved "http://registry.npm.taobao.org/socket.io/download/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b" + dependencies: + debug "~4.1.0" + engine.io "~3.3.1" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.2.0" + socket.io-parser "~3.3.0" + sshpk@^1.7.0: version "1.14.2" resolved "http://registry.npm.taobao.org/sshpk/download/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" @@ -606,6 +810,10 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" +to-array@0.1.4: + version "0.1.4" + resolved "http://registry.npm.taobao.org/to-array/download/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + tough-cookie@~2.4.3: version "2.4.3" resolved "http://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -657,3 +865,17 @@ verror@1.10.0: assert-plus "^1.0.0" core-util-is "1.0.2" extsprintf "^1.2.0" + +ws@~6.1.0: + version "6.1.3" + resolved "http://registry.npm.taobao.org/ws/download/ws-6.1.3.tgz#d2d2e5f0e3c700ef2de89080ebc0ac6e1bf3a72d" + dependencies: + async-limiter "~1.0.0" + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "http://registry.npm.taobao.org/xmlhttprequest-ssl/download/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + +yeast@0.1.2: + version "0.1.2" + resolved "http://registry.npm.taobao.org/yeast/download/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" diff --git a/frontend/config/index.js b/frontend/config/index.js index eb8a7c1a..fc6f02de 100644 --- a/frontend/config/index.js +++ b/frontend/config/index.js @@ -13,6 +13,10 @@ module.exports = { proxyTable: { '/api': { target: 'http://localhost:3000' + }, + '/ws': { + target: 'http://localhost:3000', + ws: true } }, diff --git a/frontend/package.json b/frontend/package.json index 53ead003..4c2484d3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,9 +26,11 @@ "mermaid": "^7.1.2", "monaco-editor": "^0.13.1", "normalize.css": "^7.0.0", + "socket.io-client": "^2.2.0", "vue": "^2.5.2", "vue-bus": "^1.1.0", - "vue-router": "^3.0.1" + "vue-router": "^3.0.1", + "xterm": "^3.11.0" }, "devDependencies": { "autoprefixer": "^7.1.2", diff --git a/frontend/src/components/RunPlugin.js b/frontend/src/components/RunPlugin.js index b82e69b5..b85e2cfd 100644 --- a/frontend/src/components/RunPlugin.js +++ b/frontend/src/components/RunPlugin.js @@ -43,9 +43,15 @@ const RunPlugin = (md) => { resultDiv.innerText = e.message }) ` + const runInXterm = ` + var code = '${encodeURIComponent(code).replace(/'/g, '\\\'')}' + code = decodeURIComponent(code) + runInXterm('${token.info}', code, !arguments[0].ctrlKey) + ` + const result = localStorage[`${cachePrefix}${hash}`] || '' - const resultDiv = `
${result}
` + const resultDiv = `
${result}
` const codeContent = temp(tokens, idx, options, env, slf).trim().replace(/<\/pre>$/, '') diff --git a/frontend/src/components/StatusBar.vue b/frontend/src/components/StatusBar.vue index a78ddb8b..2a470731 100644 --- a/frontend/src/components/StatusBar.vue +++ b/frontend/src/components/StatusBar.vue @@ -2,8 +2,9 @@
-
切换预览
-
切换换行
+
切换预览
+
切换换行
+
切换终端
行:{{documentInfo.line}} 列:{{documentInfo.column}} @@ -50,6 +51,9 @@ export default { toggleView () { this.$bus.emit('toggle-view') }, + toggleXterm () { + this.$bus.emit('toggle-xterm') + }, toggleWrap () { this.$bus.emit('editor-toggle-wrap') }, @@ -60,6 +64,12 @@ export default { e.stopPropagation() } + if (e.key === 'o' && e.altKey) { + this.toggleXterm() + e.preventDefault() + e.stopPropagation() + } + if (e.key === 'w' && e.altKey) { this.toggleWrap() e.preventDefault() diff --git a/frontend/src/components/View.vue b/frontend/src/components/View.vue index 127ad478..5aa24bfc 100644 --- a/frontend/src/components/View.vue +++ b/frontend/src/components/View.vue @@ -29,7 +29,7 @@
-
TOP
+
TOP
@@ -61,7 +61,8 @@ export default { value: String, fileRepo: String, fileName: String, - filePath: String + filePath: String, + showXterm: Boolean }, data () { return { @@ -393,6 +394,10 @@ button:hover { font-size: 14px; } +.scroll-to-top.show-xterm { + bottom: 45vh; +} + .scroll-to-top { user-select: none; position: fixed; diff --git a/frontend/src/components/Xterm.vue b/frontend/src/components/Xterm.vue new file mode 100644 index 00000000..9ddaa320 --- /dev/null +++ b/frontend/src/components/Xterm.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/frontend/src/pages/Home.vue b/frontend/src/pages/Home.vue index 5ccb905b..8621ec68 100644 --- a/frontend/src/pages/Home.vue +++ b/frontend/src/pages/Home.vue @@ -14,24 +14,30 @@
- - +
+
+ + +
+ +
@@ -43,6 +49,7 @@ import dayjs from 'dayjs' import Editor from '../components/Editor' import XView from '../components/View' +import Xterm from '../components/Xterm' import Tree from '../components/Tree' import StatusBar from '../components/StatusBar' import RunPlugin from '../components/RunPlugin' @@ -50,7 +57,7 @@ import File from '../file' export default { name: 'home', - components: { XView, Editor, Tree, StatusBar }, + components: { XView, Editor, Tree, StatusBar, Xterm }, data () { return { status: '请选择文件', @@ -59,7 +66,8 @@ export default { file: null, oldHash: null, timer: null, - showView: true + showView: true, + showXterm: false } }, mounted () { @@ -67,6 +75,7 @@ export default { this.restartTimer() this.$bus.on('toggle-view', this.toggleView) + this.$bus.on('toggle-xterm', this.toggleXterm) window.onbeforeunload = () => { return this.unsaved || null @@ -74,12 +83,20 @@ export default { }, beforeDestroy () { this.$bus.off('toggle-view', this.toggleView) + this.$bus.off('toggle-xterm', this.toggleXterm) this.clearTimer() }, methods: { toggleView () { this.showView = !this.showView }, + toggleXterm (flag) { + this.showXterm = flag === undefined ? !this.showXterm : !!flag + this.$nextTick(() => { + this.$refs.editor.resize() + this.$refs.xterm.init() + }) + }, editorReady () { this.$bus.emit('editor-ready') }, @@ -208,6 +225,7 @@ export default { padding-bottom: 20px; box-sizing: border-box; overflow: auto; + flex: 0 0 auto; } .show-view .editor { @@ -215,7 +233,7 @@ export default { } .editor { - height: 95vh; + /* height: 95vh; */ width: 83vw; overflow: hidden; } @@ -232,7 +250,7 @@ export default { margin: 0 auto; padding: 45px; width: 43vw; - height: 95vh; + /* height: 95vh; */ overflow: auto; box-sizing: border-box; display: none; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 2ff21672..b80d60a5 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -89,6 +89,10 @@ acorn@^5.0.0, acorn@^5.1.1, acorn@^5.2.1: version "5.3.0" resolved "http://registry.npm.taobao.org/acorn/download/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" +after@0.8.2: + version "0.8.2" + resolved "http://registry.npm.taobao.org/after/download/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + ajv-keywords@^2.0.0, ajv-keywords@^2.1.0: version "2.1.1" resolved "http://registry.npm.taobao.org/ajv-keywords/download/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" @@ -239,6 +243,10 @@ array-unique@^0.3.2: version "0.3.2" resolved "http://registry.npm.taobao.org/array-unique/download/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "http://registry.npm.taobao.org/arraybuffer.slice/download/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "http://registry.npm.taobao.org/arrify/download/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -920,6 +928,10 @@ babylon@^6.18.0: version "6.18.0" resolved "http://registry.npm.taobao.org/babylon/download/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" +backo2@1.0.2: + version "1.0.2" + resolved "http://registry.npm.taobao.org/backo2/download/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + balanced-match@^0.4.2: version "0.4.2" resolved "http://registry.npm.taobao.org/balanced-match/download/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" @@ -928,6 +940,10 @@ balanced-match@^1.0.0: version "1.0.0" resolved "http://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "http://registry.npm.taobao.org/base64-arraybuffer/download/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + base64-js@^1.0.2: version "1.2.1" resolved "http://registry.npm.taobao.org/base64-js/download/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" @@ -954,6 +970,12 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +better-assert@~1.0.0: + version "1.0.2" + resolved "http://registry.npm.taobao.org/better-assert/download/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + dependencies: + callsite "1.0.0" + big.js@^3.1.3: version "3.2.0" resolved "http://registry.npm.taobao.org/big.js/download/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" @@ -962,6 +984,10 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "http://registry.npm.taobao.org/binary-extensions/download/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" +blob@0.0.5: + version "0.0.5" + resolved "http://registry.npm.taobao.org/blob/download/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + block-stream@*: version "0.0.9" resolved "http://registry.npm.taobao.org/block-stream/download/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -1183,6 +1209,10 @@ caller-path@^0.1.0: dependencies: callsites "^0.2.0" +callsite@1.0.0: + version "1.0.0" + resolved "http://registry.npm.taobao.org/callsite/download/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + callsites@^0.2.0: version "0.2.0" resolved "http://registry.npm.taobao.org/callsites/download/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" @@ -1448,10 +1478,18 @@ commondir@^1.0.1: version "1.0.1" resolved "http://registry.npm.taobao.org/commondir/download/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" -component-emitter@^1.2.1: +component-bind@1.0.0: + version "1.0.0" + resolved "http://registry.npm.taobao.org/component-bind/download/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + +component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" +component-inherit@0.0.3: + version "0.0.3" + resolved "http://registry.npm.taobao.org/component-inherit/download/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + compressible@~2.0.11: version "2.0.12" resolved "http://registry.npm.taobao.org/compressible/download/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66" @@ -1806,7 +1844,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6. dependencies: ms "2.0.0" -debug@^3.0.1, debug@^3.1.0: +debug@^3.0.1, debug@^3.1.0, debug@~3.1.0: version "3.1.0" resolved "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -2065,6 +2103,32 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" +engine.io-client@~3.3.1: + version "3.3.2" + resolved "http://registry.npm.taobao.org/engine.io-client/download/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa" + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.1: + version "2.1.3" + resolved "http://registry.npm.taobao.org/engine.io-parser/download/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + enhanced-resolve@^3.4.0: version "3.4.1" resolved "http://registry.npm.taobao.org/enhanced-resolve/download/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e" @@ -2899,6 +2963,16 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" +has-binary2@~1.0.2: + version "1.0.3" + resolved "http://registry.npm.taobao.org/has-binary2/download/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "http://registry.npm.taobao.org/has-cors/download/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + has-flag@^1.0.0: version "1.0.0" resolved "http://registry.npm.taobao.org/has-flag/download/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" @@ -3458,6 +3532,10 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "http://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" +isarray@2.0.1: + version "2.0.1" + resolved "http://registry.npm.taobao.org/isarray/download/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + isexe@^2.0.0: version "2.0.0" resolved "http://registry.npm.taobao.org/isexe/download/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -4224,6 +4302,10 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" +object-component@0.0.3: + version "0.0.3" + resolved "http://registry.npm.taobao.org/object-component/download/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + object-copy@^0.1.0: version "0.1.0" resolved "http://registry.npm.taobao.org/object-copy/download/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -4428,6 +4510,18 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" +parseqs@0.0.5: + version "0.0.5" + resolved "http://registry.npm.taobao.org/parseqs/download/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "http://registry.npm.taobao.org/parseuri/download/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + dependencies: + better-assert "~1.0.0" + parseurl@~1.3.2: version "1.3.2" resolved "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" @@ -5535,6 +5629,33 @@ sntp@1.x.x: dependencies: hoek "2.x.x" +socket.io-client@^2.2.0: + version "2.2.0" + resolved "http://registry.npm.taobao.org/socket.io-client/download/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7" + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.3.1" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "http://registry.npm.taobao.org/socket.io-parser/download/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + sockjs-client@1.1.4: version "1.1.4" resolved "http://registry.npm.taobao.org/sockjs-client/download/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12" @@ -5891,6 +6012,10 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +to-array@0.1.4: + version "0.1.4" + resolved "http://registry.npm.taobao.org/to-array/download/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "http://registry.npm.taobao.org/to-arraybuffer/download/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -6405,14 +6530,28 @@ ws@^4.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" +ws@~6.1.0: + version "6.1.3" + resolved "http://registry.npm.taobao.org/ws/download/ws-6.1.3.tgz#d2d2e5f0e3c700ef2de89080ebc0ac6e1bf3a72d" + dependencies: + async-limiter "~1.0.0" + xml-char-classes@^1.0.0: version "1.0.0" resolved "http://registry.npm.taobao.org/xml-char-classes/download/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "http://registry.npm.taobao.org/xmlhttprequest-ssl/download/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + xtend@^4.0.0, xtend@~4.0.1: version "4.0.1" resolved "http://registry.npm.taobao.org/xtend/download/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" +xterm@^3.11.0: + version "3.11.0" + resolved "http://registry.npm.taobao.org/xterm/download/xterm-3.11.0.tgz#2c10da3e965db9170430aa7b68f8965de3ff004d" + xxhashjs@^0.2.1: version "0.2.2" resolved "http://registry.npm.taobao.org/xxhashjs/download/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" @@ -6487,3 +6626,7 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" + +yeast@0.1.2: + version "0.1.2" + resolved "http://registry.npm.taobao.org/yeast/download/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"